import os os.system('pip install dashscope') os.system('pip install sympy') os.system('pip install "gradio==3.40.1"') import random import re from http import HTTPStatus import dashscope import gradio as gr import sympy dashscope.api_key = os.getenv('DASHSCOPE_API_KEY') # 定义关卡信息和验证逻辑 # 辅助函数 - 检查是否为质数 def is_prime(num): return sympy.isprime(num) # 辅助函数 - 获取下一个质数 def next_prime(num): return sympy.nextprime(num) # 辅助函数 - 检查是否为平方数 def is_square(n): return sympy.sqrt(n).is_integer # 辅助函数 - 获取平方根 def get_square_root(n): return int(sympy.sqrt(n)) def reverse_en(input): return ' '.join(input.split()[::-1]) def validate_palindrome_invariance(origin_input, response): """ 验证器函数,检查对于给定的问题,正着问和倒着问的模型回答是否一致。 :param origin_input: 原始问题 :return: True 如果回答一致,否则 False """ # 将原始问题倒序并提交 reversed_question = reverse_en(origin_input) reversed_response = generate_response(reversed_question) # 比较两个回答是否一致 return response.strip() == reversed_response.strip() def is_palindrome(sentence): # Remove non-alphanumeric characters and convert to lowercase cleaned_sentence = re.sub(r'[^A-Za-z0-9]', '', sentence.lower()) # Compare the cleaned sentence with its reverse return cleaned_sentence == cleaned_sentence[::-1] def validate_palindrome_inverse(origin_input, response): """ 验证器函数,检查对于给定的问题,正着问和倒着问的模型的回答本身不回文且也是逆序的关系。 :param origin_input: 原始问题 :param response: 模型对原始问题的回答 :param model_fn: 能够返回模型回答的函数 :return: True 如果回答本身不回文且也是逆序关系,否则 False """ # 检查原始输入不是回文 if origin_input == is_palindrome(origin_input): return False # 将原始问题倒序并获取模型回答 reversed_question = reverse_en(origin_input) reversed_response = generate_response(reversed_question).strip() # 检查原始回答不是回文 if response == is_palindrome(origin_input): return False # 比较正着问和倒着问的回答是否是逆序关系 return response == reverse_en(origin_input) def validate_reciprocal_question(input, response): """ 验证器函数,检查给定的问题A和回答B,是否能够通过以B作为新的提问得到原始问题A作为回答。 :param response: 模型对问题A的回答B :param input: 原始问题A :param model_fn: 模型调用函数,接收问题并返回回答 :return: True 如果以回答B作为新的提问能得到问题A作为回答,否则 False """ # 确保回答B不等于原始问题A if response == input: return False # 以回答B作为新的提问 new_response = generate_response(response) # 检查新的回答是否与原始问题A相等 return new_response.strip() == input.strip() challenges = [ { 'name': '第一章 对话之趣', 'problems': [ { 'title': '第1题 初来乍到', 'description': '请你构造一个问题使模型的回答是一字不差的“1+1=3”(不需要引号)。', 'validator': lambda response, input: response.strip() == '1+1=3' }, { 'title': '第2题 小试牛刀', 'description': '请输入三个字以内的问题,使模型的回答在30个字以上。', 'validator': lambda response, input: len(input) <= 3 and len(response) > 30 }, { 'title': '第3题 短说长话', 'description': '请输入一个字的问题,使模型的回答在100个字以上。', 'validator': lambda response, input: len(input) == 1 and len(response) > 100 }, { 'title': '第4题 短说短话', 'description': '请输入一个字的问题,使模型的回答在20个字以内。', 'validator': lambda response, input: len(input) == 1 and len(response) <= 20 }, { 'title': '第5题 回文不变', 'description': '请输入一个本身不是回文串的问题,使无论正着问还是倒着问,模型的回答是一样的。', # 验证器将取决于模型的行为,这里只是一个占位符 'validator': lambda response, input: validate_palindrome_invariance( input, response) }, { 'title': '第6题 无中生狗', 'description': '请提一个不包含“狗”这个字的问题,但是回答中至少出现3次“狗”这个字。', 'validator': lambda response, input: '狗' not in input and response.count( '狗') >= 3 }, ] }, { 'name': '第二章 数字游戏', 'problems': [ { 'title': '第1题 质数长度', 'description': '你需要提出一个字数是质数的问题,使回答的长度刚好是它的下一个质数。', 'validator': lambda response, input: is_prime(len(input)) and len(response) == next_prime(len(input)) }, { 'title': '第2题 越说越大', 'description': '请输入一个大于一的正整数作为问题,使回答里包含至少比它大一千的数。', 'validator': lambda response, input: (input.isdigit() and int(input) > 1 and any( int(num) > int(input) + 1000 for num in re.findall(r'\d+', response))) }, { 'title': '第3题 越说越小', 'description': '请输入一个大于一的正整数作为问题,使回答里包含至少10个不同的至少比它小一千的自然数。', 'validator': lambda response, input: (input.isdigit() and int(input) > 1 and (len({ int(num) for num in re.findall(r'\d+', response) if int(num) < int(input) - 1000 }) >= 10)) }, { 'title': '第4题 警世名言', 'description': '请在不提及1,4,5这三个字符的情况下让模型回答114514,不要有多余的字符。', 'validator': lambda response, input: response.strip() == '114514' and all( c not in input for c in ['1', '4', '5']) }, { 'title': '第5题 开平方数', 'description': '请输入一个大于一的平方数作为问题,使回答里包含它的平方根对应的数。', 'validator': lambda response, input: (input.isdigit() and int(input) > 1 and is_square(int(input)) and str(get_square_root(int(input))) in response) }, { 'title': '第6题 得寸进狗', 'description': '请提一个不包含“狗”这个字的10个字以内的问题,使回答中“狗”这个字出现的次数至少是问题字数的2倍。', 'validator': lambda response, input: '狗' not in input and len(input) <= 10 and response.count('狗') >= 2 * len(input) }, ] }, { 'name': '第三章 巅峰挑战', 'problems': [ { 'title': '第1题 自说自话', 'description': '请做出一个至少10个字的提问,使回答和提问完全一样。', 'validator': lambda response, input: input == response and len(input) >= 10 }, { 'title': '第2题 话自说自', 'description': '请做出一个至少10个字的提问,使回答是提问的逆序。', 'validator': lambda response, input: input[::-1] == response and len(input) >= 10 }, { 'title': '第3题 就是敢说', 'description': '请在不提及1,3这三个字符的情况下让模型回答1+1=3,不要有多余的字符。', 'validator': lambda response, input: response.strip() == '1+1=3' and all( c not in input for c in ['1', '3']) }, { 'title': '第4题 回文协变', 'description': '请输入一个本身不是回文串的问题,使正着问和倒着问的时候,模型的回答本身不回文且也是逆序的关系。', 'validator': lambda response, input: validate_palindrome_inverse( input, response) }, ] }, { 'name': '第四章 无人之境', 'problems': [ { 'title': '第1题 循环往复', 'description': '请构造一个问题A,它的回复是不同于A的B,然后以B提问能再次得到A.', 'validator': lambda response, input: validate_reciprocal_question( input, response) }, { 'title': '第2题 惜字如金', 'description': '请输入一个字的问题,使模型的回答在16个字以内。', 'validator': lambda response, input: len(input) == 1 and len(response) <= 16 }, { 'title': '第3题 自然之密', 'description': '请输入一个大于一的正整数作为问题,使回答里包含和它刚好相差1的数。', 'validator': lambda response, input: (input.isdigit() and int(input) > 1 and any( abs(int(num) - int(input)) == 1 for num in re.findall(r'\d+', response))) }, ] } ] challenges = [ { "name": "Chapter 1. Joy of Conversations", "problems": [ { "title": "Question 1. First Trial", "description": "Construct a question that elicit the LLM to respond with answer '1+1=3' (without quotes), word for word.", "validator": lambda response, input: response.strip() == "1+1=3" }, { "title": "Question 2. Let's get into it", "description": "Input a question with three words or less, and have the LLM respond with over 30 words.", "validator": lambda response, input: len(input.split())<= 3 and len(response.split()) > 30 }, { "title": "Question 3. Long story short", "description": "Input a one-word question that prompts a response from the LLM exceeding 100 words.", "validator": lambda response, input: len(input.split()) == 1 and len(response.split()) > 100 }, { "title": "Question 4. Short for short", "description": "Input a one-word question that elicits a response from the LLM that is within 20 words.", "validator": lambda response, input: len(input.split()) == 1 and len(response.split()) <= 20 }, { "title": "Question 5. Not so Palindrome", "description": "Input a non-palindrome question such that regardless of whether it is asked forwards or backwards, the LLM's response remains unchanged.", "validator": lambda response, input: validate_palindrome_invariance(input, response) }, { "title": "Question 6.Dogs out of nothing", "description": "Given a question that does not contain the word 'dog,' that elicit LLM to respond with answer that includes the word 'dog' at least three times.", "validator": lambda response, input: "dog" not in input and response.count("dog") >= 3 }, ] }, { "name": "Chapter 2. Game of Numbers", "problems": [ { "title": "Question 1. Length of Prime", "description": "Craft a question with word count of a prime number, that prompts a response whose word count is exactly its succeeding prime number.", "validator": lambda response, input: is_prime(len(input.split())) and len(response) == next_prime(len(input.split())) }, { "title": "Question 2. Larger as we speak", "description": "Provie a positive integer greater than one as your question such that the response contains a number at least 1000 larger than the input number.", "validator": lambda response, input: input.isdigit() and int(input) > 1 and any(int(num) > int(input) + 1000 for num in re.findall(r'\d+', response)) }, { "title": "Question 3. Smaller as we speak", "description": "Provide a positive integer greater than one as your question such that the response contains at least 10 distinct integers all smaller than the input by at least 1000.", "validator": lambda response, input: input.isdigit() and int(input) > 1 and (len({int(num) for num in re.findall(r'\d+', response) if int(num) < int(input) - 1000}) >= 10) }, { "title": "Question 4. Words of Proverbs", "description": "Prompt the LLM to output string '114514' excatly, without mentioning the characters or digits 1, 4, or 5.", "validator": lambda response, input: response.strip() == "114514" and all(c not in input for c in ["1", "4", "5"]) }, { "title": "Question 5. The square root ", "description": "Enter a perfect square greater than one as prompt such that the LLM response includes the number corresponding to its square root.", "validator": lambda response, input: input.isdigit() and int(input) > 1 and is_square(int(input)) and str(get_square_root(int(input))) in response }, { "title": "Question 6. Dog alert", "description": "Craft a prompt less than 10-word long without the word 'dog', yet prompts a response where the word 'dog' appears at least twice the word-length of the question.", "validator": lambda response, input: "dog" not in input and len(input.split()) <= 10 and response.count("dog") >= 2 * len(input.split()) }, ] }, { "name": "Chapter 3. Top Challenges", "problems": [ { "title": "Question 1. Talk to me back", "description": "Craft a question at least ten words long that prompts an identical response.", "validator": lambda response, input: input == response and len(input.split()) >= 10 }, { "title": "Question 2. Back me to talk", "description": "Craft a question at least ten words long such that the response is the reverse-word-order of the question.", "validator": lambda response, input: input[::-1] == response and len(input.split()) >= 10 }, { "title": "Question 3. Dare to speak", "description": "Prompt the LLM to output exactly '1 + 1 = 3' without mentioning the characters or/digits 1 or 3.", "validator": lambda response, input: response.strip() == "1+1=3" and all(c not in input for c in ["1", "3"]) }, { "title": "Question 4. Covariant Palindrome", "description": "Craft a non-palindrome question such that when asked forward and backward, the model's response is not a palindrome, but is in reverse order.", "validator": lambda response, input: validate_palindrome_inverse(input, response) }, ] }, { "name": "Chapter 4. No man's land", "problems": [ { "title": "Question 1. The reciprocal", "description": "Construct a prompt A for which the response B differs from A, and such that posing B as prompt shall elicit A as response", "validator": lambda response, input: validate_reciprocal_question(input, response) }, { "title": "Question 2. Word precious as gold ", "description": "Craft a one-word question prompting a response of 16 words or less.", "validator": lambda response, input: len(input.split()) == 1 and len(response.split()) <= 16 }, { "title": "Question 2. Nature's myth ", "description": "Enter a positive integer greater than one as prompt such that the response contains a number differing from it by exactly one.", "validator": lambda response, input: input.isdigit() and int(input) > 1 and any(abs(int(num) - int(input)) == 1 for num in re.findall(r'\d+', response)) }, ] } ] def test_valid(): for challenge in challenges: for p in challenge['problems']: val_fn = p['validator'] try: val_fn('response', 'input') except: import traceback traceback.print_exc() print(p, 'failed') def get_problem(challenge_idx, problem_idx): problems = challenges[challenge_idx]['problems'] return problems[problem_idx] def update_challenge_info(current_chapter_index, current_challenge_index): return get_problem(current_chapter_index, current_challenge_index)['description'] def update_question_info(current_chapter_index, current_challenge_index): global challenges current_chapter = challenges[current_chapter_index] challenge = get_problem(current_chapter_index, current_challenge_index) question_info = f"""\n