zjowowen's picture
merge files from main branch
0d8bebc
import re
from typing import Optional, Tuple
import sympy
from .question import register_question
from .math_tools import get_all_numbers
CN_TEXT_1 = """
第二章第一题(质数长度),你需要提出一个字数是质数的问题,使回答的长度刚好是它的下一个质数。
"""
EN_TEXT_1 = """
For the first question in chapter 2, You need to come up with a question that has a prime number of words, so the answer's length is exactly the next prime number.
"""
def _is_prime(v):
return sympy.isprime(v)
def _next_prime(v):
while v:
v += 1
if _is_prime(v):
return v
def _cn_checker_1(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
qs_length = len(user_text.strip())
if not _is_prime(qs_length):
return False, f'问题长度为{qs_length},非质数'
answer_value = len(answer_text)
next_prime = _next_prime(qs_length)
if answer_value != next_prime:
return False, f'下一个质数为{next_prime},但回答长度为{answer_value}'
return True, None
def _en_words(text: str):
return len(re.findall(r'\w+', text))
def _en_checker_1(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
qs_length = _en_words(user_text.strip())
if not _is_prime(qs_length):
return False, f'The question has a length of {qs_length}, which is not a prime number'
answer_value = _en_words(answer_text)
next_prime = _next_prime(qs_length)
if answer_value != next_prime:
return False, f'The next prime number is {next_prime}, but the answer\'s length is {answer_value}'
return True, None
register_question(
{
'cn': CN_TEXT_1,
'en': EN_TEXT_1,
},
checkers={
'cn': _cn_checker_1,
'en': _en_checker_1,
},
name={'cn': '2-1 质数长度', 'en': '2-1'},
level=2
)
CN_TEXT_2 = """
第二章第二题(越说越大),请输入一个大于一的正整数作为问题,使回答里包含至少比它大一千的数。
"""
EN_TEXT_2 = """
For the second question in chapter 2, Please enter a positive integer greater than one as a question, so that the answer contains a number that is at least one thousand more than it.
"""
def _cn_checker_2(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
except (TypeError, ValueError):
return False, f'输入内容{user_text!r},并非一个大于1的正整数'
for value_item in get_all_numbers(answer_text):
if value_item >= value + 1000:
return True, f'检测到输出中数字{value_item},满足要求'
return False, f'未在输出中检测到不少于{value + 1000}的数字'
def _en_checker_2(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
except (TypeError, ValueError):
return False, f'You entered {user_text!r}, which is not a positive integer greater than 1'
for value_item in get_all_numbers(answer_text):
if value_item >= value + 1000:
return True, f'Detected the number {value_item} in the output, which meets the requirement'
return False, f'Did not detect a number of at least {value + 1000} in the output'
register_question(
{
'cn': CN_TEXT_2,
'en': EN_TEXT_2,
},
checkers={
'cn': _cn_checker_2,
'en': _en_checker_2,
},
name={'cn': '2-2 越说越大', 'en': '2-2'},
level=2
)
CN_TEXT_3 = """
第二章第三题(越说越小),请输入一个大于一的正整数作为问题,使回答里包含至少10个不同的至少比它小一千的自然数。
"""
EN_TEXT_3 = """
For the third question in chapter 2, Please enter a positive integer greater than one as a question, so that the answer contains at least 10 different natural numbers, each of them at least 1000 less than the question.
"""
def _cn_checker_3(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
except (TypeError, ValueError):
return False, f'输入内容{user_text!r},并非一个大于1的正整数'
collected_values = []
for value_item in get_all_numbers(answer_text):
if value_item <= value - 1000:
collected_values.append(value_item)
collected_values = sorted(set(collected_values))
if len(collected_values) >= 10:
return True, f'检测到{len(collected_values)}个不大于{value - 1000}的数字:{collected_values!r}'
else:
return False, f'检测到{len(collected_values)}个不大于{value - 1000}的数字,未达到10个:{collected_values!r}'
def _en_checker_3(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
except (TypeError, ValueError):
return False, f'You entered {user_text!r}, which is not a positive integer greater than 1'
collected_values = []
for value_item in get_all_numbers(answer_text):
if value_item <= value - 1000:
collected_values.append(value_item)
collected_values = sorted(set(collected_values))
if len(collected_values) >= 10:
return True, f'Detected {len(collected_values)} numbers not greater than {value - 1000}: {collected_values!r}'
else:
return False, f'Detected {len(collected_values)} numbers not greater than {value - 1000}, ' \
f'but it doesn\'t reach 10: {collected_values!r}'
register_question(
{
'cn': CN_TEXT_3,
'en': EN_TEXT_3,
},
checkers={
'cn': _cn_checker_3,
'en': _en_checker_3,
},
name={'cn': '2-3 越说越小', 'en': '2-3'},
level=2,
)
CN_TEXT_4 = """
第二章第四题(警世名言),请在不提及1,4,5这三个字符的情况下让模型回答114514,不要有多余的字符。
"""
EN_TEXT_4 = """
For the fourth question in chapter 2, Please make the model answer "114514" without mentioning the characters 1, 4, and 5, and without any extra characters.
"""
def _cn_checker_4(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
if "1" in user_text or "4" in user_text or "5" in user_text:
return False, '请不要在提问中出现1、4、5三个数字'
return answer_text.strip() == '114514', None
def _en_checker_4(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
if "1" in user_text or "4" in user_text or "5" in user_text:
return False, 'Please don\'t include the numbers 1, 4, and 5 in the question'
return answer_text.strip() == '114514', None
register_question(
{
'cn': CN_TEXT_4,
'en': EN_TEXT_4,
},
checkers={
'cn': _cn_checker_4,
'en': _en_checker_4,
},
name={'cn': '2-4 警世名言', 'en': '2-4'},
level=2,
)
CN_TEXT_5 = """
第二章第五题(开平方数),请输入一个大于一的平方数作为问题,使回答里包含它的平方根对应的数。
"""
EN_TEXT_5 = """
For the fifth question in chapter 2, Please provide a square number greater than one as the question, and the answer should include the number corresponding to its square root.
"""
def _cn_checker_5(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
if int(value ** 0.5) ** 2 != value:
raise ValueError
except (TypeError, ValueError):
return False, f'输入内容{user_text!r},并非一个大于1的平方数'
sq = int(value ** 0.5)
for value_item in get_all_numbers(answer_text):
if value_item == sq:
return True, f'检测到平方根数{sq}'
else:
return False, f'未检测到平方根数{sq}'
def _en_checker_5(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
try:
value = int(user_text.strip())
if value <= 1:
raise ValueError
if int(value ** 0.5) ** 2 != value:
raise ValueError
except (TypeError, ValueError):
return False, f'The input, {user_text!r}, is not a square number greater than 1'
sq = int(value ** 0.5)
for value_item in get_all_numbers(answer_text):
if value_item == sq:
return True, f'Detected square root: {sq}'
else:
return False, f'Square root {sq} not detected'
register_question(
{
'cn': CN_TEXT_5,
'en': EN_TEXT_5,
},
checkers={
'cn': _cn_checker_5,
'en': _en_checker_5,
},
name={'cn': '2-5 开平方数', 'en': '2-5'},
level=2,
)
CN_TEXT_6 = """
第二章第六题(得寸进狗),请提一个不包含“狗”这个字的10个字以内的问题,使回答中“狗”这个字出现的次数至少是问题字数的2倍。
"""
EN_TEXT_6 = """
For the sixth question in chapter 2, Please ask a question in under 10 words without the word "dog" and ensure that the word "dog" appears at least twice in the answer for each word in the question.
"""
def _cn_checker_6(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
if len(user_text) > 10:
return False, '问题不得超过10个字'
if '狗' in user_text:
return False, '问题不得包含“狗”字'
dog_count = len(re.findall('狗', answer_text))
if dog_count >= len(user_text) * 2:
return True, f'“狗”字的出现次数为{dog_count}次'
else:
return False, f'“狗”字的出现次数为{dog_count}次,未达到{len(user_text) * 2}次'
def _en_checker_6(question_text: str, user_text: str, answer_text: str) -> Tuple[bool, Optional[str]]:
q_words = re.findall(r'\w+', user_text.lower())
if len(q_words) > 10:
return False, 'The question must not exceed 10 words'
if any(word in {'dog', 'dogs'} for word in q_words):
return False, 'The question must not contain the word "dog" or "dogs"'
a_words = re.findall(r'\w+', answer_text.lower())
a_dog_count = sum(1 if word in {'dog', 'dogs'} else 0 for word in a_words)
if a_dog_count >= len(q_words) * 2:
return True, f'The word "dog" (or "dogs") appears {a_dog_count} times.'
else:
return False, f'The word "dog" (or "dogs") appears {a_dog_count} times, ' \
f'which is less than {len(q_words) * 2} times.'
register_question(
{
'cn': CN_TEXT_6,
'en': EN_TEXT_6,
},
checkers={
'cn': _cn_checker_6,
'en': _en_checker_6,
},
name={'cn': '2-6 得寸进狗', 'en': '2-6'},
level=2
)