littlebird13 commited on
Commit
6713bb5
1 Parent(s): 736aa15

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +314 -0
app.py ADDED
@@ -0,0 +1,314 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.system('pip install dashscope')
3
+ # os.system('pip install "gradio==3.40.1"')
4
+ import gradio as gr
5
+ import random
6
+ from http import HTTPStatus
7
+ import dashscope
8
+ import sympy
9
+ import re
10
+
11
+ dashscope.api_key = os.getenv('DASHSCOPE_API_KEY')
12
+
13
+
14
+ # 定义关卡信息和验证逻辑
15
+
16
+ # 辅助函数 - 检查是否为质数
17
+ def is_prime(num):
18
+ return sympy.isprime(num)
19
+
20
+ # 辅助函数 - 获取下一个质数
21
+ def next_prime(num):
22
+ return sympy.nextprime(num)
23
+
24
+ # 辅助函数 - 检查是否为平方数
25
+ def is_square(n):
26
+ return sympy.sqrt(n).is_integer
27
+
28
+ # 辅助函数 - 获取平方根
29
+ def get_square_root(n):
30
+ return int(sympy.sqrt(n))
31
+
32
+ def validate_palindrome_invariance(origin_input, response):
33
+ """
34
+ 验证器函数,检查对于给定的问题,正着问和倒着问的模型回答是否一致。
35
+
36
+ :param origin_input: 原始问题
37
+ :return: True 如果回答一致,否则 False
38
+ """
39
+
40
+ # 将原始问题倒序并提交
41
+ reversed_question = origin_input[::-1]
42
+ reversed_response = generate_response(reversed_question)
43
+
44
+ # 比较两个回答是否一致
45
+ return response.strip() == reversed_response.strip()
46
+
47
+ def validate_palindrome_inverse(origin_input, response):
48
+ """
49
+ 验证器函数,检查对于给定的问题,正着问和倒着问的模型的回答本身不回文且也是逆序的关系。
50
+
51
+ :param origin_input: 原始问题
52
+ :param response: 模型对原始问题的回答
53
+ :param model_fn: 能够返回模型回答的函数
54
+ :return: True 如果回答本身不回文且也是逆序关系,否则 False
55
+ """
56
+
57
+ # 检查原始输入不是回文
58
+ if origin_input == origin_input[::-1]:
59
+ return False
60
+
61
+ # 将原始问题倒序并获取模型回答
62
+ reversed_question = origin_input[::-1]
63
+ reversed_response = generate_response(reversed_question).strip()
64
+
65
+ # 检查原始回答不是回文
66
+ if response == response[::-1]:
67
+ return False
68
+
69
+ # 比较正着问和倒着问的回答是否是逆序关系
70
+ return response == reversed_response[::-1]
71
+
72
+ def validate_reciprocal_question(input, response):
73
+ """
74
+ 验证器函数,检查给定的问题A和回答B,是否能够通过以B作为新的提问得到原始问题A作为回答。
75
+
76
+ :param response: 模型对问题A的回答B
77
+ :param input: 原始问题A
78
+ :param model_fn: 模型调用函数,接收问题并返回回答
79
+ :return: True 如果以回答B作为新的提问能得到问题A作为回答,否则 False
80
+ """
81
+
82
+ # 确保回答B不等于原始问题A
83
+ if response == input:
84
+ return False
85
+
86
+ # 以回答B作为新的提问
87
+ new_response = generate_response(response)
88
+
89
+ # 检查新的回答是否与原始问题A相等
90
+ return new_response.strip() == input.strip()
91
+
92
+ challenges = [
93
+ {
94
+ "name": "第一章 对话之趣",
95
+ "problems": [
96
+ {
97
+ "title": "第1题 初来乍到",
98
+ "description": "请你构造一个问题使模型的回答是一字不差的“1+1=3”(不需要引号)。",
99
+ "validator": lambda response, input: response.strip() == "1+1=3"
100
+ },
101
+ {
102
+ "title": "第2题 小试牛刀",
103
+ "description": "请输入三个字以内的问题,使模型的回答在30个字以上。",
104
+ "validator": lambda response, input: len(input) <= 3 and len(response) > 30
105
+ },
106
+ {
107
+ "title": "第3题 短说长话",
108
+ "description": "请输入一个字的问题,使模型的回答在100个字以上。",
109
+ "validator": lambda response, input: len(input) == 1 and len(response) > 100
110
+ },
111
+ {
112
+ "title": "第4题 短说短话",
113
+ "description": "请输入一个字的问题,使模型的回答在20个字以内。",
114
+ "validator": lambda response, input: len(input) == 1 and len(response) <= 20
115
+ },
116
+ {
117
+ "title": "第5题 回文不变",
118
+ "description": "请输入一个本身不是回文串的问题,使无论正着问还是倒着问,模型的回答是一样的。",
119
+ # 验证器将取决于模型的行为,这里只是一个占位符
120
+ "validator": lambda response, input: validate_palindrome_invariance(input, response)
121
+ },
122
+ {
123
+ "title": "第6题 无中生狗",
124
+ "description": "请提一个不包含“狗”这个字的问题,但是回答中至少出现3次“狗”这个字。",
125
+ "validator": lambda response, input: "狗" not in input and response.count("狗") >= 3
126
+ },
127
+ ]
128
+ },
129
+ {
130
+ "name": "第二章 数字游戏",
131
+ "problems": [
132
+ {
133
+ "title": "第1题 质数长度",
134
+ "description": "你需要提出一个字数是质数的问题,使回答的长度刚好是它的下一个质数。",
135
+ "validator": lambda response, input: is_prime(len(input)) and len(response) == next_prime(len(input))
136
+ },
137
+ {
138
+ "title": "第2题 越说越大",
139
+ "description": "请输入一个大于一的正整数作为问题,使回答里包含至少比它大一千的数。",
140
+ "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))
141
+ },
142
+ {
143
+ "title": "第3题 越说越小",
144
+ "description": "请输入一个大于一的正整数作为问题,使回答里包含至少10个不同的至少比它小一千的自然数。",
145
+ "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)
146
+ },
147
+ {
148
+ "title": "第4题 警世名言",
149
+ "description": "请在不提及1,4,5这三个字符的情况下让模型回答114514,不要有多余的字符。",
150
+ "validator": lambda response, input: response.strip() == "114514" and all(c not in input for c in ["1", "4", "5"])
151
+ },
152
+ {
153
+ "title": "第5题 开平方数",
154
+ "description": "请输入一个大于一的平方数作为问题,使回答里包含它的平方根对应的数。",
155
+ "validator": lambda response, input: input.isdigit() and int(input) > 1 and is_square(int(input)) and str(get_square_root(int(input))) in response
156
+ },
157
+ {
158
+ "title": "第6题 得寸进狗",
159
+ "description": "请提一个不包含“狗”这个字的10个字以内的问题,使回答中“狗”这个字出现的次数至少是问题字数的2倍。",
160
+ "validator": lambda response, input: "狗" not in input and len(input) <= 10 and response.count("狗") >= 2 * len(input)
161
+ },
162
+ ]
163
+ },
164
+ {
165
+ "name": "第三章 巅峰挑战",
166
+ "problems": [
167
+ {
168
+ "title": "第1题 自说自话",
169
+ "description": "请做出一个至少10个字的提问,使回答和提问完全一样。",
170
+ "validator": lambda response, input: input == response and len(input) >= 10
171
+ },
172
+ {
173
+ "title": "第2题 话自说自",
174
+ "description": "请做出一个至少10个字的提问,使回答是提问的逆序。",
175
+ "validator": lambda response, input: input[::-1] == response and len(input) >= 10
176
+ },
177
+ {
178
+ "title": "第3题 就是敢说",
179
+ "description": "请在不提及1,3这三个字符的情况下让模型回答1+1=3,不要有多余的字符。",
180
+ "validator": lambda response, input: response.strip() == "1+1=3" and all(c not in input for c in ["1", "3"])
181
+ },
182
+ {
183
+ "title": "第4题 回文协变",
184
+ "description": "请输入一个本身不是回文串的问题,使正着问和倒着问的时候,模型的回答本身不回文且也是逆序的关系。",
185
+ "validator": lambda response, input: validate_palindrome_inverse(input, response)
186
+ },
187
+ ]
188
+ },
189
+ {
190
+ "name": "第四章 无人之境",
191
+ "problems": [
192
+ {
193
+ "title": "第1题 循环往复",
194
+ "description": "请构造一个问题A,它的回复是不同于A的B,然后以B提问能再次得到A.",
195
+ "validator": lambda response, input: validate_reciprocal_question(input, response)
196
+ },
197
+ {
198
+ "title": "第2题 惜字如金",
199
+ "description": "请输入一个字的问题,使模型的回答在16个字以内。",
200
+ "validator": lambda response, input: len(input) == 1 and len(response) <= 16
201
+ },
202
+ {
203
+ "title": "第3题 自然之密",
204
+ "description": "请输入一个大于一的正整数作为问题,使回答里包含和它刚好相差1的数。",
205
+ "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))
206
+ },
207
+ ]
208
+ }
209
+ ]
210
+
211
+
212
+
213
+
214
+ def get_problem(challenge_idx, problem_idx):
215
+ problems = challenges[challenge_idx]['problems']
216
+ return problems[problem_idx]
217
+
218
+ def update_challenge_info(current_chapter_index, current_challenge_index):
219
+ return get_problem(current_chapter_index, current_challenge_index)["description"]
220
+
221
+ def update_question_info(current_chapter_index, current_challenge_index):
222
+ global challenges
223
+ current_chapter = challenges[current_chapter_index]
224
+ challenge = get_problem(current_chapter_index, current_challenge_index)
225
+ question_info = f"""\n<center><font size=4>{current_chapter["name"]}</center>\n\n <center><font size=3>{challenge["title"]}</center>"""
226
+ return question_info
227
+
228
+
229
+ def validate_challenge(response, input, state):
230
+ print('in validate_challenge')
231
+ assert 'current_chapter_index' in state, 'current_chapter_index not found in state'
232
+ assert 'current_challenge_index' in state, 'current_challenge_index not found in state'
233
+ current_chapter_index = state['current_chapter_index']
234
+ current_challenge_index = state['current_challenge_index']
235
+ # 获取当前章节
236
+ current_chapter = challenges[current_chapter_index]
237
+ # 获取当前挑战
238
+ challenge = current_chapter["problems"][current_challenge_index]
239
+
240
+ if challenge["validator"](response, input):
241
+ challenge_result = "挑战成功!进入下一关。"
242
+ # 检查是否还有更多挑战在当前章节
243
+ if current_challenge_index < len(current_chapter["problems"]) - 1:
244
+ # 移动到当前章节的下一个挑战
245
+ current_challenge_index += 1
246
+ else:
247
+ # 如果当前章节的挑战已经完成,移动到下一个章节
248
+ current_challenge_index = 0
249
+ if current_chapter_index < len(challenges) - 1:
250
+ current_chapter_index += 1
251
+ else:
252
+ challenge_result = "所有挑战完成!"
253
+ else:
254
+ challenge_result = "挑战失败,请再试一次。"
255
+ state['current_chapter_index'] = current_chapter_index
256
+ state['current_challenge_index'] = current_challenge_index
257
+ print('update state: ', state)
258
+
259
+ return challenge_result, \
260
+ update_question_info(current_chapter_index, current_challenge_index), \
261
+ update_challenge_info(current_chapter_index, current_challenge_index)
262
+
263
+
264
+ def generate_response(input):
265
+ messages = [{'role': 'system', 'content': """You are a helpful assistant."""},
266
+ {'role': 'user', 'content': input}]
267
+ response = dashscope.Generation.call(
268
+ model='qwen-max',
269
+ messages=messages,
270
+ # set the random seed, optional, default to 1234 if not set
271
+ seed=random.randint(1, 10000),
272
+ result_format='message', # set the result to be "message" format.
273
+ top_p = 0.8
274
+ )
275
+ if response.status_code == HTTPStatus.OK:
276
+ return response.output.choices[0].message.content
277
+ else:
278
+ gr.Error("网络连接错误,请重试。")
279
+
280
+ def on_submit(input, state):
281
+ response = generate_response(input)
282
+ history = [(input,response)]
283
+ print(history)
284
+ challenge_result, question_info, challenge_info = validate_challenge(response, input, state)
285
+ print('validate_challenge done')
286
+ return challenge_result, history, question_info, challenge_info
287
+
288
+
289
+ # Gradio界面构建
290
+ block = gr.Blocks()
291
+
292
+ with block as demo:
293
+ state = gr.State(dict(current_challenge_index=0,
294
+ current_chapter_index=0))
295
+ current_chapter_index = 0
296
+ current_challenge_index = 0
297
+ gr.Markdown("""<center><font size=6>完蛋!我被LLM包围了!</center>""")
298
+ gr.Markdown("""<font size=3>欢迎来玩LLM Riddles复刻版:完蛋!我被LLM包围了!
299
+
300
+ 你将通过本游戏对大型语言模型产生更深刻的理解。
301
+
302
+ 在本游戏中,你需要构造一个提给一个大型语言模型的问题,使得它回复的答案符合要求。""")
303
+ question_info = gr.Markdown(update_question_info(current_chapter_index, current_challenge_index))
304
+ challenge_info = gr.Textbox(value=update_challenge_info(current_chapter_index, current_challenge_index), label="当前挑战", disabled=True)
305
+ challenge_result = gr.Textbox(label="挑战结果", disabled=True)
306
+ chatbot = gr.Chatbot(lines=8, label='Qwen-max', elem_classes="control-height")
307
+ message = gr.Textbox(lines=2, label='输入')
308
+
309
+ with gr.Row():
310
+ submit = gr.Button("🚀 发送")
311
+
312
+ submit.click(on_submit, inputs=[message, state], outputs=[challenge_result, chatbot, question_info, challenge_info])
313
+
314
+ demo.queue().launch(height=800, share=True)