import re from typing import Optional, Tuple import sympy from .question import register_question 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 re.findall('[-+]?\d+', answer_text): value_item = int(value_item) 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 )