Spaces:
Runtime error
Runtime error
Merge branch 'vlad' into 'feature-wormhole'
Browse filesData-driven quiz
See merge request tangibleai/community/mathtext-fastapi!12
- app.py +109 -93
- mathtext_fastapi/conversation_manager.py +2 -2
- mathtext_fastapi/v2_conversation_manager.py +2 -2
- pyproject.toml +6 -3
- requirements.txt +15 -6
- scripts/make_request.py +23 -22
- scripts/quiz/__init__.py +0 -0
- scripts/quiz/data.csv +56 -0
- scripts/quiz/generators.py +0 -33
- scripts/quiz/hints.py +0 -32
- scripts/quiz/questions.py +0 -116
- scripts/quiz/utils.py +0 -13
app.py
CHANGED
@@ -1,12 +1,10 @@
|
|
1 |
"""FastAPI endpoint
|
2 |
To run locally use 'uvicorn app:app --host localhost --port 7860'
|
|
|
|
|
3 |
"""
|
4 |
import ast
|
5 |
-
import
|
6 |
-
import scripts.quiz.hints as hints
|
7 |
-
import scripts.quiz.questions as questions
|
8 |
-
import scripts.quiz.utils as utils
|
9 |
-
|
10 |
from fastapi import FastAPI, Request
|
11 |
from fastapi.responses import JSONResponse
|
12 |
from fastapi.staticfiles import StaticFiles
|
@@ -146,168 +144,186 @@ async def evaluate_user_message_with_nlu_api(request: Request):
|
|
146 |
message_data = data_dict.get('message_data', '')
|
147 |
nlu_response = evaluate_message_with_nlu(message_data)
|
148 |
return JSONResponse(content=nlu_response)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
|
150 |
|
151 |
-
@app.post("/
|
152 |
async def ask_math_question(request: Request):
|
153 |
-
"""Generate a question
|
154 |
|
155 |
Input
|
156 |
-
request.body: json - amount of correct and incorrect answers in the account
|
157 |
{
|
158 |
-
'
|
159 |
-
'
|
160 |
-
'level': 'easy'
|
161 |
}
|
162 |
|
163 |
Output
|
164 |
-
context: dict - the information for the current state
|
165 |
{
|
166 |
'text': 'What is 1+2?',
|
167 |
-
'
|
168 |
-
'
|
169 |
-
'number_correct': 0,
|
170 |
-
'number_incorrect': 0,
|
171 |
-
'hints_used': 0
|
172 |
}
|
173 |
"""
|
174 |
data_dict = await request.json()
|
175 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
176 |
-
|
177 |
-
|
178 |
-
level = message_data['level']
|
179 |
|
180 |
-
return JSONResponse(generators.start_interactive_math(
|
181 |
|
182 |
|
183 |
@app.post("/hint")
|
184 |
async def get_hint(request: Request):
|
185 |
-
"""Generate a hint
|
186 |
|
187 |
Input
|
188 |
-
request.body:
|
189 |
{
|
190 |
-
'
|
191 |
-
'
|
192 |
-
'
|
193 |
-
'number_incorrect': 0,
|
194 |
-
'level': 'easy',
|
195 |
-
'hints_used': 0
|
196 |
}
|
197 |
|
198 |
Output
|
199 |
-
context: dict - the information for the current state
|
200 |
{
|
201 |
-
'text': 'What is
|
202 |
-
'
|
203 |
-
'
|
204 |
-
'number_correct': 0,
|
205 |
-
'number_incorrect': 0,
|
206 |
-
'level': 'easy',
|
207 |
-
'hints_used': 0
|
208 |
}
|
209 |
"""
|
210 |
data_dict = await request.json()
|
211 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
number_incorrect = message_data['number_incorrect']
|
216 |
-
level = message_data['level']
|
217 |
-
hints_used = message_data['hints_used']
|
218 |
|
219 |
-
return JSONResponse(hints.generate_hint(
|
220 |
|
221 |
|
222 |
-
@app.post("/
|
223 |
-
async def
|
224 |
-
"""Generate a
|
225 |
|
226 |
Input
|
227 |
-
request.body: json - level
|
228 |
{
|
229 |
-
'
|
|
|
|
|
230 |
}
|
231 |
|
232 |
Output
|
233 |
-
context: dict - the information for the current state
|
234 |
{
|
235 |
-
|
236 |
-
|
|
|
|
|
237 |
}
|
238 |
"""
|
239 |
data_dict = await request.json()
|
240 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
241 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
242 |
|
243 |
-
return JSONResponse(questions.generate_question_data(
|
244 |
|
245 |
|
246 |
-
@app.post("/
|
247 |
-
async def
|
248 |
-
"""Generate
|
249 |
|
250 |
Input
|
251 |
-
request.body: json - level
|
252 |
{
|
253 |
-
'
|
|
|
254 |
}
|
255 |
|
256 |
-
Output
|
257 |
-
|
258 |
-
{
|
259 |
-
"current_number": 10,
|
260 |
-
"ordinal_number": 2,
|
261 |
-
"times": 1
|
262 |
-
}
|
263 |
"""
|
264 |
data_dict = await request.json()
|
265 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
266 |
-
|
267 |
-
|
268 |
|
|
|
269 |
|
270 |
-
|
271 |
-
|
272 |
-
|
|
|
273 |
|
274 |
Input
|
275 |
-
request.body: json - level
|
276 |
{
|
277 |
-
|
278 |
-
|
279 |
-
"times": 1
|
280 |
}
|
281 |
|
282 |
-
Output
|
283 |
-
|
284 |
-
... 1 2 3
|
285 |
-
1 2 3 ...
|
286 |
"""
|
287 |
data_dict = await request.json()
|
288 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
|
|
|
|
|
|
|
|
|
|
293 |
|
294 |
|
295 |
-
@app.post("/
|
296 |
-
async def
|
297 |
-
"""
|
298 |
|
299 |
Input
|
300 |
-
request.body: json - level
|
301 |
{
|
302 |
-
|
303 |
-
|
|
|
304 |
}
|
305 |
|
306 |
Output
|
307 |
-
|
308 |
"""
|
309 |
data_dict = await request.json()
|
310 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
311 |
-
|
312 |
-
|
313 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
"""FastAPI endpoint
|
2 |
To run locally use 'uvicorn app:app --host localhost --port 7860'
|
3 |
+
or
|
4 |
+
`python -m uvicorn app:app --reload --host localhost --port 7860`
|
5 |
"""
|
6 |
import ast
|
7 |
+
import mathactive.microlessons.num_one as num_one_quiz
|
|
|
|
|
|
|
|
|
8 |
from fastapi import FastAPI, Request
|
9 |
from fastapi.responses import JSONResponse
|
10 |
from fastapi.staticfiles import StaticFiles
|
|
|
144 |
message_data = data_dict.get('message_data', '')
|
145 |
nlu_response = evaluate_message_with_nlu(message_data)
|
146 |
return JSONResponse(content=nlu_response)
|
147 |
+
|
148 |
+
|
149 |
+
@app.post("/num_one")
|
150 |
+
async def num_one(request: Request):
|
151 |
+
"""
|
152 |
+
Input:
|
153 |
+
{
|
154 |
+
"user_id": 1,
|
155 |
+
"message_text": 5,
|
156 |
+
}
|
157 |
+
Output:
|
158 |
+
{
|
159 |
+
'messages':
|
160 |
+
["Let's", 'practice', 'counting', '', '', '46...', '47...', '48...', '49', '', '', 'After', '49,', 'what', 'is', 'the', 'next', 'number', 'you', 'will', 'count?\n46,', '47,', '48,', '49'],
|
161 |
+
'input_prompt': '50',
|
162 |
+
'state': 'question'
|
163 |
+
}
|
164 |
+
"""
|
165 |
+
data_dict = await request.json()
|
166 |
+
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
167 |
+
user_id = message_data['user_id']
|
168 |
+
message_text = message_data['message_text']
|
169 |
+
return num_one_quiz.process_user_message(user_id, message_text)
|
170 |
|
171 |
|
172 |
+
@app.post("/start")
|
173 |
async def ask_math_question(request: Request):
|
174 |
+
"""Generate a question data
|
175 |
|
176 |
Input
|
|
|
177 |
{
|
178 |
+
'difficulty': 0.1,
|
179 |
+
'do_increase': True | False
|
|
|
180 |
}
|
181 |
|
182 |
Output
|
|
|
183 |
{
|
184 |
'text': 'What is 1+2?',
|
185 |
+
'difficulty': 0.2,
|
186 |
+
'question_numbers': [3, 1, 4]
|
|
|
|
|
|
|
187 |
}
|
188 |
"""
|
189 |
data_dict = await request.json()
|
190 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
191 |
+
difficulty = message_data['difficulty']
|
192 |
+
do_increase = message_data['do_increase']
|
|
|
193 |
|
194 |
+
return JSONResponse(generators.start_interactive_math(difficulty, do_increase))
|
195 |
|
196 |
|
197 |
@app.post("/hint")
|
198 |
async def get_hint(request: Request):
|
199 |
+
"""Generate a hint data
|
200 |
|
201 |
Input
|
|
|
202 |
{
|
203 |
+
'start': 5,
|
204 |
+
'step': 1,
|
205 |
+
'difficulty': 0.1
|
|
|
|
|
|
|
206 |
}
|
207 |
|
208 |
Output
|
|
|
209 |
{
|
210 |
+
'text': 'What number is greater than 4 and less than 6?',
|
211 |
+
'difficulty': 0.1,
|
212 |
+
'question_numbers': [5, 1, 6]
|
|
|
|
|
|
|
|
|
213 |
}
|
214 |
"""
|
215 |
data_dict = await request.json()
|
216 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
217 |
+
start = message_data['start']
|
218 |
+
step = message_data['step']
|
219 |
+
difficulty = message_data['difficulty']
|
|
|
|
|
|
|
220 |
|
221 |
+
return JSONResponse(hints.generate_hint(start, step, difficulty))
|
222 |
|
223 |
|
224 |
+
@app.post("/question")
|
225 |
+
async def ask_math_question(request: Request):
|
226 |
+
"""Generate a question data
|
227 |
|
228 |
Input
|
|
|
229 |
{
|
230 |
+
'start': 5,
|
231 |
+
'step': 1,
|
232 |
+
'question_num': 1 # optional
|
233 |
}
|
234 |
|
235 |
Output
|
|
|
236 |
{
|
237 |
+
'question': 'What is 1+2?',
|
238 |
+
'start': 5,
|
239 |
+
'step': 1,
|
240 |
+
'answer': 6
|
241 |
}
|
242 |
"""
|
243 |
data_dict = await request.json()
|
244 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
245 |
+
start = message_data['start']
|
246 |
+
step = message_data['step']
|
247 |
+
arg_tuple = (start, step)
|
248 |
+
try:
|
249 |
+
question_num = message_data['question_num']
|
250 |
+
arg_tuple += (question_num,)
|
251 |
+
except KeyError:
|
252 |
+
pass
|
253 |
|
254 |
+
return JSONResponse(questions.generate_question_data(*arg_tuple))
|
255 |
|
256 |
|
257 |
+
@app.post("/difficulty")
|
258 |
+
async def get_hint(request: Request):
|
259 |
+
"""Generate a number matching difficulty
|
260 |
|
261 |
Input
|
|
|
262 |
{
|
263 |
+
'difficulty': 0.01,
|
264 |
+
'do_increase': True
|
265 |
}
|
266 |
|
267 |
+
Output - value from 0.01 to 0.99 inclusively:
|
268 |
+
0.09
|
|
|
|
|
|
|
|
|
|
|
269 |
"""
|
270 |
data_dict = await request.json()
|
271 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
272 |
+
difficulty = message_data['difficulty']
|
273 |
+
do_increase = message_data['do_increase']
|
274 |
|
275 |
+
return JSONResponse(utils.get_next_difficulty(difficulty, do_increase))
|
276 |
|
277 |
+
|
278 |
+
@app.post("/start_step")
|
279 |
+
async def get_hint(request: Request):
|
280 |
+
"""Generate a start and step values
|
281 |
|
282 |
Input
|
|
|
283 |
{
|
284 |
+
'difficulty': 0.01,
|
285 |
+
'path_to_csv_file': 'scripts/quiz/data.csv' # optional
|
|
|
286 |
}
|
287 |
|
288 |
+
Output - tuple (start, step):
|
289 |
+
(5, 1)
|
|
|
|
|
290 |
"""
|
291 |
data_dict = await request.json()
|
292 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
293 |
+
difficulty = message_data['difficulty']
|
294 |
+
arg_tuple = (difficulty,)
|
295 |
+
try:
|
296 |
+
path_to_csv_file = message_data['path_to_csv_file']
|
297 |
+
arg_tuple += (path_to_csv_file,)
|
298 |
+
except KeyError:
|
299 |
+
pass
|
300 |
+
|
301 |
+
return JSONResponse(utils.get_next_difficulty(*arg_tuple))
|
302 |
|
303 |
|
304 |
+
@app.post("/sequence")
|
305 |
+
async def generate_question(request: Request):
|
306 |
+
"""Generate a sequence from start, step and optional separator parameter
|
307 |
|
308 |
Input
|
|
|
309 |
{
|
310 |
+
'start': 5,
|
311 |
+
'step': 1,
|
312 |
+
'sep': ', ' # optional
|
313 |
}
|
314 |
|
315 |
Output
|
316 |
+
5, 6, 7
|
317 |
"""
|
318 |
data_dict = await request.json()
|
319 |
message_data = ast.literal_eval(data_dict.get('message_data', '').get('message_body', ''))
|
320 |
+
start = message_data['start']
|
321 |
+
step = message_data['step']
|
322 |
+
arg_tuple = (start, step)
|
323 |
+
try:
|
324 |
+
sep = message_data['sep']
|
325 |
+
arg_tuple += (sep,)
|
326 |
+
except KeyError:
|
327 |
+
pass
|
328 |
+
|
329 |
+
return JSONResponse(utils.convert_sequence_to_string(*arg_tuple))
|
mathtext_fastapi/conversation_manager.py
CHANGED
@@ -14,8 +14,8 @@ from mathtext_fastapi.math_subtraction_fsm import MathSubtractionFSM
|
|
14 |
from supabase import create_client
|
15 |
from transitions import Machine
|
16 |
|
17 |
-
from
|
18 |
-
from
|
19 |
|
20 |
load_dotenv()
|
21 |
|
|
|
14 |
from supabase import create_client
|
15 |
from transitions import Machine
|
16 |
|
17 |
+
from mathactive.generators import start_interactive_math
|
18 |
+
from mathactive.hints import generate_hint
|
19 |
|
20 |
load_dotenv()
|
21 |
|
mathtext_fastapi/v2_conversation_manager.py
CHANGED
@@ -16,8 +16,8 @@ from mathtext_fastapi.math_subtraction_fsm import MathSubtractionFSM
|
|
16 |
from supabase import create_client
|
17 |
from transitions import Machine
|
18 |
|
19 |
-
from
|
20 |
-
from
|
21 |
|
22 |
load_dotenv()
|
23 |
|
|
|
16 |
from supabase import create_client
|
17 |
from transitions import Machine
|
18 |
|
19 |
+
from mathactive.generators import start_interactive_math
|
20 |
+
from mathactive.hints import generate_hint
|
21 |
|
22 |
load_dotenv()
|
23 |
|
pyproject.toml
CHANGED
@@ -20,14 +20,17 @@ classifiers = [
|
|
20 |
|
21 |
|
22 |
[tool.poetry.dependencies]
|
|
|
23 |
mathtext = {git = "https://gitlab.com/tangibleai/community/mathtext", rev = "main"}
|
24 |
-
fastapi = "0.
|
25 |
pydantic = "*"
|
26 |
-
python = "^3.8
|
27 |
-
requests = "2.27.*"
|
28 |
sentencepiece = "0.1.*"
|
29 |
supabase = "*"
|
30 |
uvicorn = "0.17.*"
|
|
|
|
|
31 |
|
32 |
[tool.poetry.group.dev.dependencies]
|
33 |
pytest = "^7.2"
|
|
|
20 |
|
21 |
|
22 |
[tool.poetry.dependencies]
|
23 |
+
mathactive = {git = "[email protected]:tangibleai/community/mathactive.git", rev = "vlad"}
|
24 |
mathtext = {git = "https://gitlab.com/tangibleai/community/mathtext", rev = "main"}
|
25 |
+
fastapi = "^0.90.0"
|
26 |
pydantic = "*"
|
27 |
+
python = "^3.8"
|
28 |
+
requests = "2.27.*"
|
29 |
sentencepiece = "0.1.*"
|
30 |
supabase = "*"
|
31 |
uvicorn = "0.17.*"
|
32 |
+
pandas = "^1.5.3"
|
33 |
+
scipy = "^1.10.1"
|
34 |
|
35 |
[tool.poetry.group.dev.dependencies]
|
36 |
pytest = "^7.2"
|
requirements.txt
CHANGED
@@ -2,15 +2,24 @@ dill
|
|
2 |
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.4.1/en_core_web_sm-3.4.1-py3-none-any.whl
|
3 |
fuzzywuzzy
|
4 |
jsonpickle
|
5 |
-
mathtext
|
6 |
-
|
|
|
|
|
|
|
|
|
7 |
openpyxl
|
8 |
-
pydantic==1.10.*
|
9 |
python-Levenshtein
|
10 |
-
requests==2.27.*
|
11 |
-
sentencepiece==0.1.*
|
12 |
sentence-transformers
|
13 |
supabase
|
14 |
transitions
|
15 |
-
uvicorn
|
|
|
|
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.4.1/en_core_web_sm-3.4.1-py3-none-any.whl
|
3 |
fuzzywuzzy
|
4 |
jsonpickle
|
5 |
+
mathtext
|
6 |
+
mathactive
|
7 |
+
fastapi
|
8 |
+
pydantic
|
9 |
+
requests
|
10 |
+
sentencepiece
|
11 |
openpyxl
|
|
|
12 |
python-Levenshtein
|
|
|
|
|
13 |
sentence-transformers
|
14 |
supabase
|
15 |
transitions
|
16 |
+
uvicorn
|
17 |
+
pandas
|
18 |
+
scipy
|
19 |
|
20 |
+
# Deprecated
|
21 |
+
# mathtext @ git+https://gitlab.com/tangibleai/community/mathtext@main
|
22 |
+
# fastapi==0.74.*
|
23 |
+
# pydantic==1.10.*
|
24 |
+
# requests==2.27.*
|
25 |
+
# sentencepiece==0.1.*
|
scripts/make_request.py
CHANGED
@@ -84,34 +84,35 @@ run_simulated_request('v2/manager', '5')
|
|
84 |
# run_simulated_request('manager', '')
|
85 |
# run_simulated_request('manager', 'add')
|
86 |
# run_simulated_request('manager', 'subtract')
|
87 |
-
|
88 |
-
#
|
89 |
-
# '
|
90 |
-
# '
|
91 |
# })
|
92 |
# run_simulated_request("hint", {
|
93 |
-
# '
|
94 |
-
# '
|
95 |
-
# '
|
96 |
-
# 'number_incorrect': 0,
|
97 |
-
# 'level': 'easy',
|
98 |
-
# 'hints_used': 0
|
99 |
-
# })
|
100 |
-
# run_simulated_request("generate_question", {
|
101 |
-
# 'level': 'medium'
|
102 |
# })
|
103 |
-
# run_simulated_request("
|
104 |
-
# '
|
|
|
|
|
105 |
# })
|
106 |
-
# run_simulated_request("
|
107 |
-
#
|
108 |
-
#
|
109 |
-
# "times": 1
|
110 |
# })
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
114 |
# })
|
|
|
115 |
# run_simulated_request('manager', 'exit')
|
116 |
|
117 |
|
|
|
84 |
# run_simulated_request('manager', '')
|
85 |
# run_simulated_request('manager', 'add')
|
86 |
# run_simulated_request('manager', 'subtract')
|
87 |
+
|
88 |
+
# run_simulated_request("start", {
|
89 |
+
# 'difficulty': 0.04,
|
90 |
+
# 'do_increase': True
|
91 |
# })
|
92 |
# run_simulated_request("hint", {
|
93 |
+
# 'start': 5,
|
94 |
+
# 'step': 1,
|
95 |
+
# 'difficulty': 0.56 # optional
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
# })
|
97 |
+
# run_simulated_request("question", {
|
98 |
+
# 'start': 2,
|
99 |
+
# 'step': 1,
|
100 |
+
# 'question_num': 2 # optional
|
101 |
# })
|
102 |
+
# run_simulated_request("difficulty", {
|
103 |
+
# 'difficulty': 0.01,
|
104 |
+
# 'do_increase': False # True | False
|
|
|
105 |
# })
|
106 |
+
run_simulated_request("num_one", {
|
107 |
+
"user_id": "1",
|
108 |
+
"message_text": "61",
|
109 |
+
})
|
110 |
+
# run_simulated_request("sequence", {
|
111 |
+
# 'start': 2,
|
112 |
+
# 'step': 1,
|
113 |
+
# 'sep': '... '
|
114 |
# })
|
115 |
+
|
116 |
# run_simulated_request('manager', 'exit')
|
117 |
|
118 |
|
scripts/quiz/__init__.py
ADDED
File without changes
|
scripts/quiz/data.csv
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
difficulty,start
|
2 |
+
0.01,1
|
3 |
+
0.02,0
|
4 |
+
0.05,5
|
5 |
+
0.07,10
|
6 |
+
0.08,14
|
7 |
+
0.1,20
|
8 |
+
0.11,22
|
9 |
+
0.13,27
|
10 |
+
0.14,28
|
11 |
+
0.16,30
|
12 |
+
0.17,32
|
13 |
+
0.18,34
|
14 |
+
0.2,37
|
15 |
+
0.21,39
|
16 |
+
0.23,42
|
17 |
+
0.25,43
|
18 |
+
0.27,46
|
19 |
+
0.3,50
|
20 |
+
0.34,57
|
21 |
+
0.35,64
|
22 |
+
0.37,78
|
23 |
+
0.39,89
|
24 |
+
0.41,100
|
25 |
+
0.44,112
|
26 |
+
0.45,130
|
27 |
+
0.48,147
|
28 |
+
0.5,164
|
29 |
+
0.52,180
|
30 |
+
0.55,195
|
31 |
+
0.58,209
|
32 |
+
0.6,223
|
33 |
+
0.61,236
|
34 |
+
0.63,248
|
35 |
+
0.64,259
|
36 |
+
0.65,271
|
37 |
+
0.67,284
|
38 |
+
0.69,296
|
39 |
+
0.7,308
|
40 |
+
0.72,321
|
41 |
+
0.73,333
|
42 |
+
0.75,346
|
43 |
+
0.78,359
|
44 |
+
0.8,370
|
45 |
+
0.81,385
|
46 |
+
0.83,399
|
47 |
+
0.84,408
|
48 |
+
0.87,420
|
49 |
+
0.88,435
|
50 |
+
0.89,447
|
51 |
+
0.9,458
|
52 |
+
0.93,469
|
53 |
+
0.94,483
|
54 |
+
0.96,494
|
55 |
+
0.97,500
|
56 |
+
0.99,513
|
scripts/quiz/generators.py
DELETED
@@ -1,33 +0,0 @@
|
|
1 |
-
from .questions import generate_question_data
|
2 |
-
from .utils import get_next_level
|
3 |
-
|
4 |
-
|
5 |
-
def start_interactive_math(right_answers=0, wrong_answers=0, level="easy"):
|
6 |
-
if wrong_answers > 2:
|
7 |
-
wrong_answers = 0
|
8 |
-
right_answers = 0
|
9 |
-
level = get_next_level(level, False)
|
10 |
-
elif right_answers > 2:
|
11 |
-
right_answers = 0
|
12 |
-
wrong_answers = 0
|
13 |
-
level = get_next_level(level)
|
14 |
-
|
15 |
-
question_data = generate_question_data(level)
|
16 |
-
question = question_data['question']
|
17 |
-
right_answer = question_data['answer']
|
18 |
-
cur_num = question_data['current_number']
|
19 |
-
ord_num = question_data['ordinal_number']
|
20 |
-
times = question_data['times']
|
21 |
-
|
22 |
-
numbers_group = [cur_num, ord_num, times]
|
23 |
-
output = {
|
24 |
-
"text": question,
|
25 |
-
"question_numbers": numbers_group,
|
26 |
-
"right_answer": right_answer,
|
27 |
-
'number_correct': right_answers,
|
28 |
-
'number_incorrect': wrong_answers,
|
29 |
-
'level': level,
|
30 |
-
"hints_used": 0
|
31 |
-
}
|
32 |
-
return output
|
33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/quiz/hints.py
DELETED
@@ -1,32 +0,0 @@
|
|
1 |
-
import random
|
2 |
-
|
3 |
-
|
4 |
-
def generate_hint(question_nums, right_answer, right_answers, wrong_answers, level, hints_used):
|
5 |
-
ord_num = question_nums[1] # ordinal number
|
6 |
-
equation = right_answer - 2 * ord_num - 1
|
7 |
-
min_num = equation if equation > 0 else 0
|
8 |
-
seq_before = " ".join(
|
9 |
-
[str(num) for num in range(right_answer - ord_num, min_num, -ord_num)][::-1]
|
10 |
-
) # sequence before right answer
|
11 |
-
seq_after = " ".join(
|
12 |
-
[str(num) for num in range(right_answer + ord_num, right_answer + 2 * ord_num + 1, ord_num)]
|
13 |
-
) # sequence after right answer
|
14 |
-
hints = [
|
15 |
-
f"What number will fill the gap in a sequence {seq_before} ... {seq_after}?",
|
16 |
-
f"What number is {ord_num} in the account after {right_answer - ord_num}?",
|
17 |
-
f"What number is {ord_num} in the account before {right_answer + ord_num}?",
|
18 |
-
f"What number is greater than {right_answer - 1} and less than {right_answer + 1}?"
|
19 |
-
]
|
20 |
-
rand_hint = random.choice(hints)
|
21 |
-
hints_used += 1
|
22 |
-
|
23 |
-
output = {
|
24 |
-
"text": rand_hint,
|
25 |
-
"question_numbers": question_nums,
|
26 |
-
"right_answer": right_answer,
|
27 |
-
'number_correct': right_answers,
|
28 |
-
'number_incorrect': wrong_answers,
|
29 |
-
'level': level,
|
30 |
-
"hints_used": hints_used
|
31 |
-
}
|
32 |
-
return output
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/quiz/questions.py
DELETED
@@ -1,116 +0,0 @@
|
|
1 |
-
import random
|
2 |
-
from typing import Literal
|
3 |
-
|
4 |
-
|
5 |
-
def generate_question_data(level: Literal["easy", "medium", "hard"] = "easy"):
|
6 |
-
"""generate question, its numbers and proper answer"""
|
7 |
-
|
8 |
-
nums = generate_numbers_by_level(level)
|
9 |
-
cur_num = nums['current_number'] # current number
|
10 |
-
ord_num = nums['ordinal_number'] # ordinal number
|
11 |
-
seq_up_by_one = generate_number_sequence(cur_num, ord_num=1, times=1) # sequence with ord_num = 1, times = 1
|
12 |
-
|
13 |
-
count_up_by_one_questions = [
|
14 |
-
{
|
15 |
-
"question": f"Let's practice counting. After {cur_num}, what number is next?\n{seq_up_by_one}",
|
16 |
-
"current_number": cur_num,
|
17 |
-
"ordinal_number": 1,
|
18 |
-
"times": 1,
|
19 |
-
"answer": cur_num + 1
|
20 |
-
}
|
21 |
-
]
|
22 |
-
seq_up_by_ord = generate_number_sequence(cur_num, ord_num, times=1) # sequence with times = 1
|
23 |
-
count_up_by_ord_questions = [
|
24 |
-
{
|
25 |
-
"question": f"What number comes {ord_num} number after {cur_num}?\n{seq_up_by_ord}",
|
26 |
-
"current_number": cur_num,
|
27 |
-
"ordinal_number": ord_num,
|
28 |
-
"times": 1,
|
29 |
-
"answer": cur_num + ord_num
|
30 |
-
},
|
31 |
-
{
|
32 |
-
"question": f"If we count up {ord_num} from {cur_num}, what number is next?\n{seq_up_by_ord}",
|
33 |
-
"current_number": cur_num,
|
34 |
-
"ordinal_number": ord_num,
|
35 |
-
"times": 1,
|
36 |
-
"answer": cur_num + ord_num
|
37 |
-
}
|
38 |
-
]
|
39 |
-
times = 1 if level == "easy" else nums['times']
|
40 |
-
times_ord_seq = generate_number_sequence(cur_num, ord_num, times)
|
41 |
-
times_ord_questions = [
|
42 |
-
{
|
43 |
-
"question": f"We're counting up by {times}s. What number is {ord_num} after {cur_num}?\n{times_ord_seq}",
|
44 |
-
"current_number": cur_num,
|
45 |
-
"ordinal_number": ord_num,
|
46 |
-
"times": times,
|
47 |
-
"answer": cur_num + ord_num * times
|
48 |
-
}
|
49 |
-
]
|
50 |
-
times_only_seq = generate_number_sequence(cur_num, 1, times) # sequence with ordinal number = 1
|
51 |
-
times_only_questions = [
|
52 |
-
{
|
53 |
-
"question": f"Let's count up by {times}s. What number is next if we start from {cur_num}?\n{times_only_seq}",
|
54 |
-
"current_number": cur_num,
|
55 |
-
"ordinal_number": 1,
|
56 |
-
"times": times,
|
57 |
-
"answer": cur_num + times
|
58 |
-
}
|
59 |
-
]
|
60 |
-
questions = [*count_up_by_one_questions, *count_up_by_ord_questions, *times_only_questions, *times_ord_questions]
|
61 |
-
random_choice = random.choice(questions)
|
62 |
-
return random_choice
|
63 |
-
|
64 |
-
|
65 |
-
def generate_numbers_by_level(level: Literal["easy", "medium", "hard"] = "easy"):
|
66 |
-
"""generate current number, ordinal number and times parameter
|
67 |
-
|
68 |
-
returns
|
69 |
-
dict with params:
|
70 |
-
:param current_number: current number
|
71 |
-
:param ordinal numebr: the number we count up by
|
72 |
-
:param times: the number of times we count up by ordinal number"""
|
73 |
-
|
74 |
-
if level == "easy":
|
75 |
-
cur_num = random.randint(1, 8)
|
76 |
-
ord_num = random.randint(1, 2)
|
77 |
-
times = 1
|
78 |
-
elif level == "medium":
|
79 |
-
cur_num = random.randint(1, 94)
|
80 |
-
ord_num = random.randint(1, 3)
|
81 |
-
times = random.randint(1, 2)
|
82 |
-
elif level == "hard":
|
83 |
-
cur_num = random.randint(1, 488)
|
84 |
-
ord_num = random.randint(1, 4)
|
85 |
-
times = random.randint(1, 2)
|
86 |
-
|
87 |
-
return {
|
88 |
-
"current_number": cur_num,
|
89 |
-
"ordinal_number": ord_num,
|
90 |
-
"times": times
|
91 |
-
}
|
92 |
-
|
93 |
-
|
94 |
-
def generate_number_sequence(cur_num, ord_num, times=1):
|
95 |
-
"""generate one of 2 sequences. For example we want 55 to be a right answer, then sequences can be:
|
96 |
-
52 53 54 ...
|
97 |
-
... 56 57 58
|
98 |
-
|
99 |
-
parameters
|
100 |
-
:cur_num: current number
|
101 |
-
:ord_num: ordinal number
|
102 |
-
:times: times"""
|
103 |
-
max_num = cur_num + times * ord_num
|
104 |
-
|
105 |
-
seq_before = [str(num) for num in range(max_num - times, 0, -times)][:3][::-1]
|
106 |
-
seq_after = [str(num) for num in range(max_num + times, max_num + 4 * times, times)]
|
107 |
-
seq_before.append("...")
|
108 |
-
seq_after.insert(0, "...")
|
109 |
-
|
110 |
-
seqs = []
|
111 |
-
if len(seq_before) == 4:
|
112 |
-
seqs.append(seq_before)
|
113 |
-
if len(seq_after) == 4:
|
114 |
-
seqs.append(seq_after)
|
115 |
-
rand_seq = " ".join(random.choice(seqs))
|
116 |
-
return rand_seq
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
scripts/quiz/utils.py
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
from typing import Literal
|
2 |
-
|
3 |
-
def get_next_level(cur_level, levep_up: Literal[True, False] = True):
|
4 |
-
if levep_up:
|
5 |
-
if cur_level == "easy":
|
6 |
-
return "medium"
|
7 |
-
else:
|
8 |
-
return "hard"
|
9 |
-
else:
|
10 |
-
if cur_level == "medium":
|
11 |
-
return "easy"
|
12 |
-
else:
|
13 |
-
return "medium"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|