Add mini test compatibility.
This commit is contained in:
91
app.py
91
app.py
@@ -3,6 +3,8 @@ import threading
|
|||||||
from flask import Flask, request
|
from flask import Flask, request
|
||||||
from flask_jwt_extended import JWTManager, jwt_required
|
from flask_jwt_extended import JWTManager, jwt_required
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
|
||||||
|
from helper.ExamVariant import ExamVariant
|
||||||
from helper.api_messages import *
|
from helper.api_messages import *
|
||||||
from helper.exercises import *
|
from helper.exercises import *
|
||||||
from helper.file_helper import delete_files_older_than_one_day
|
from helper.file_helper import delete_files_older_than_one_day
|
||||||
@@ -161,6 +163,7 @@ def save_listening():
|
|||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
parts = data.get('parts')
|
parts = data.get('parts')
|
||||||
|
minTimer = data.get('minTimer', LISTENING_MIN_TIMER_DEFAULT)
|
||||||
template = getListeningTemplate()
|
template = getListeningTemplate()
|
||||||
id = str(uuid.uuid4())
|
id = str(uuid.uuid4())
|
||||||
for i, part in enumerate(parts, start=0):
|
for i, part in enumerate(parts, start=0):
|
||||||
@@ -175,6 +178,12 @@ def save_listening():
|
|||||||
template["parts"][i]["audio"]["source"] = file_url
|
template["parts"][i]["audio"]["source"] = file_url
|
||||||
template["parts"][i]["exercises"] = part["exercises"]
|
template["parts"][i]["exercises"] = part["exercises"]
|
||||||
|
|
||||||
|
if minTimer != LISTENING_MIN_TIMER_DEFAULT:
|
||||||
|
template["minTimer"] = minTimer
|
||||||
|
template["variant"] = ExamVariant.PARTIAL.value
|
||||||
|
else:
|
||||||
|
template["variant"] = ExamVariant.FULL.value
|
||||||
|
|
||||||
(result, id) = save_to_db_with_id("listening", template, id)
|
(result, id) = save_to_db_with_id("listening", template, id)
|
||||||
if result:
|
if result:
|
||||||
return {**template, "id": id}
|
return {**template, "id": id}
|
||||||
@@ -293,25 +302,25 @@ def get_writing_task_2_general_question():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
|
|
||||||
|
# THE SAVING OF WRITING IS DONE WITHOUT THE API ON THE FRONTEND
|
||||||
@app.route('/writing', methods=['POST'])
|
# @app.route('/writing', methods=['POST'])
|
||||||
@jwt_required()
|
# @jwt_required()
|
||||||
def save_writing_task():
|
# def save_writing_task():
|
||||||
try:
|
# try:
|
||||||
data = request.get_json()
|
# data = request.get_json()
|
||||||
exercises = data.get('exercises')
|
# exercises = data.get('exercises')
|
||||||
template = getWritingTemplate()
|
# template = getWritingTemplate()
|
||||||
id = str(uuid.uuid4())
|
# id = str(uuid.uuid4())
|
||||||
for i, exercise in enumerate(exercises, start=0):
|
# for i, exercise in enumerate(exercises, start=0):
|
||||||
template["exercises"][i]["prompt"] = exercise
|
# template["exercises"][i]["prompt"] = exercise
|
||||||
|
#
|
||||||
(result, id) = save_to_db_with_id("writing", template, id)
|
# (result, id) = save_to_db_with_id("writing", template, id)
|
||||||
if result:
|
# if result:
|
||||||
return {**template, "id": id}
|
# return {**template, "id": id}
|
||||||
else:
|
# else:
|
||||||
raise Exception("Failed to save writing: " + template)
|
# raise Exception("Failed to save writing: " + template)
|
||||||
except Exception as e:
|
# except Exception as e:
|
||||||
return str(e)
|
# return str(e)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/speaking_task_1', methods=['POST'])
|
@app.route('/speaking_task_1', methods=['POST'])
|
||||||
@@ -377,6 +386,7 @@ def get_speaking_task_1_question():
|
|||||||
token_count = count_tokens(gen_sp1_question)["n_tokens"]
|
token_count = count_tokens(gen_sp1_question)["n_tokens"]
|
||||||
response = make_openai_instruct_call(GPT_3_5_TURBO_INSTRUCT, gen_sp1_question, token_count, GEN_FIELDS,
|
response = make_openai_instruct_call(GPT_3_5_TURBO_INSTRUCT, gen_sp1_question, token_count, GEN_FIELDS,
|
||||||
GEN_QUESTION_TEMPERATURE)
|
GEN_QUESTION_TEMPERATURE)
|
||||||
|
response["type"] = 1
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
@@ -446,6 +456,7 @@ def get_speaking_task_2_question():
|
|||||||
token_count = count_tokens(gen_sp2_question)["n_tokens"]
|
token_count = count_tokens(gen_sp2_question)["n_tokens"]
|
||||||
response = make_openai_instruct_call(GPT_3_5_TURBO_INSTRUCT, gen_sp2_question, token_count, GEN_FIELDS,
|
response = make_openai_instruct_call(GPT_3_5_TURBO_INSTRUCT, gen_sp2_question, token_count, GEN_FIELDS,
|
||||||
GEN_QUESTION_TEMPERATURE)
|
GEN_QUESTION_TEMPERATURE)
|
||||||
|
response["type"] = 2
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
@@ -466,6 +477,7 @@ def get_speaking_task_3_question():
|
|||||||
# Remove the numbers from the questions only if the string starts with a number
|
# Remove the numbers from the questions only if the string starts with a number
|
||||||
response["questions"] = [re.sub(r"^\d+\.\s*", "", question) if re.match(r"^\d+\.", question) else question for
|
response["questions"] = [re.sub(r"^\d+\.\s*", "", question) if re.match(r"^\d+\.", question) else question for
|
||||||
question in response["questions"]]
|
question in response["questions"]]
|
||||||
|
response["type"] = 3
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return str(e)
|
return str(e)
|
||||||
@@ -544,7 +556,15 @@ def save_speaking():
|
|||||||
try:
|
try:
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
exercises = data.get('exercises')
|
exercises = data.get('exercises')
|
||||||
|
minTimer = data.get('minTimer', SPEAKING_MIN_TIMER_DEFAULT)
|
||||||
template = getSpeakingTemplate()
|
template = getSpeakingTemplate()
|
||||||
|
|
||||||
|
if minTimer != SPEAKING_MIN_TIMER_DEFAULT:
|
||||||
|
template["minTimer"] = minTimer
|
||||||
|
template["variant"] = ExamVariant.PARTIAL.value
|
||||||
|
else:
|
||||||
|
template["variant"] = ExamVariant.FULL.value
|
||||||
|
|
||||||
id = str(uuid.uuid4())
|
id = str(uuid.uuid4())
|
||||||
app.logger.info('Received request to save speaking with id: ' + id)
|
app.logger.info('Received request to save speaking with id: ' + id)
|
||||||
thread_event.set()
|
thread_event.set()
|
||||||
@@ -646,22 +666,23 @@ def get_reading_passage_3_question():
|
|||||||
return str(e)
|
return str(e)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/reading', methods=['POST'])
|
# THE SAVING OF READING IS DONE WITHOUT THE API ON THE FRONTEND
|
||||||
@jwt_required()
|
# @app.route('/reading', methods=['POST'])
|
||||||
def save_reading_passage():
|
# @jwt_required()
|
||||||
try:
|
# def save_reading_passage():
|
||||||
data = request.get_json()
|
# try:
|
||||||
parts = data.get('parts')
|
# data = request.get_json()
|
||||||
template = getReadingTemplate()
|
# parts = data.get('parts')
|
||||||
template["parts"] = parts
|
# template = getReadingTemplate()
|
||||||
id = str(uuid.uuid4())
|
# template["parts"] = parts
|
||||||
(result, id) = save_to_db_with_id("reading", template, id)
|
# id = str(uuid.uuid4())
|
||||||
if result:
|
# (result, id) = save_to_db_with_id("reading", template, id)
|
||||||
return {**template, "id": id}
|
# if result:
|
||||||
else:
|
# return {**template, "id": id}
|
||||||
raise Exception("Failed to save reading: " + template)
|
# else:
|
||||||
except Exception as e:
|
# raise Exception("Failed to save reading: " + template)
|
||||||
return str(e)
|
# except Exception as e:
|
||||||
|
# return str(e)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/level', methods=['GET'])
|
@app.route('/level', methods=['GET'])
|
||||||
|
|||||||
6
helper/ExamVariant.py
Normal file
6
helper/ExamVariant.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class ExamVariant(Enum):
|
||||||
|
FULL = "full"
|
||||||
|
PARTIAL = "partial"
|
||||||
@@ -27,6 +27,10 @@ TOTAL_LISTENING_SECTION_2_EXERCISES = 10
|
|||||||
TOTAL_LISTENING_SECTION_3_EXERCISES = 10
|
TOTAL_LISTENING_SECTION_3_EXERCISES = 10
|
||||||
TOTAL_LISTENING_SECTION_4_EXERCISES = 10
|
TOTAL_LISTENING_SECTION_4_EXERCISES = 10
|
||||||
|
|
||||||
|
LISTENING_MIN_TIMER_DEFAULT = 30
|
||||||
|
WRITING_MIN_TIMER_DEFAULT = 60
|
||||||
|
SPEAKING_MIN_TIMER_DEFAULT = 14
|
||||||
|
|
||||||
EN_US_VOICES = [
|
EN_US_VOICES = [
|
||||||
{'Gender': 'Female', 'Id': 'Salli', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Salli',
|
{'Gender': 'Female', 'Id': 'Salli', 'LanguageCode': 'en-US', 'LanguageName': 'US English', 'Name': 'Salli',
|
||||||
'SupportedEngines': ['neural', 'standard']},
|
'SupportedEngines': ['neural', 'standard']},
|
||||||
|
|||||||
@@ -38,43 +38,58 @@ TYLER_CHRISTOPHER = "03c796f8ed274bb38f19e893bcbc6121"
|
|||||||
|
|
||||||
def create_videos_and_save_to_db(exercises, template, id):
|
def create_videos_and_save_to_db(exercises, template, id):
|
||||||
# Speaking 1
|
# Speaking 1
|
||||||
|
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||||
|
found_exercises_1 = [element for element in exercises if element.get('type') == 1]
|
||||||
|
# Check if any elements were found
|
||||||
|
if found_exercises_1:
|
||||||
|
exercise_1 = found_exercises_1[0]
|
||||||
app.app.logger.info('Creating video for speaking part 1')
|
app.app.logger.info('Creating video for speaking part 1')
|
||||||
sp1_result = create_video(exercises[0]["question"], random.choice(list(AvatarEnum)))
|
sp1_result = create_video(exercise_1["question"], random.choice(list(AvatarEnum)))
|
||||||
if sp1_result is not None:
|
if sp1_result is not None:
|
||||||
sound_file_path = VIDEO_FILES_PATH + sp1_result
|
sound_file_path = VIDEO_FILES_PATH + sp1_result
|
||||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp1_result
|
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp1_result
|
||||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||||
sp1_video_path = firebase_file_path
|
sp1_video_path = firebase_file_path
|
||||||
sp1_video_url = url
|
sp1_video_url = url
|
||||||
template["exercises"][0]["text"] = exercises[0]["question"]
|
template["exercises"][0]["text"] = exercise_1["question"]
|
||||||
template["exercises"][0]["title"] = exercises[0]["topic"]
|
template["exercises"][0]["title"] = exercise_1["topic"]
|
||||||
template["exercises"][0]["video_url"] = sp1_video_url
|
template["exercises"][0]["video_url"] = sp1_video_url
|
||||||
template["exercises"][0]["video_path"] = sp1_video_path
|
template["exercises"][0]["video_path"] = sp1_video_path
|
||||||
else:
|
else:
|
||||||
app.app.logger.error("Failed to create video for part 1 question: " + exercises[0]["question"])
|
app.app.logger.error("Failed to create video for part 1 question: " + exercise_1["question"])
|
||||||
|
|
||||||
# Speaking 2
|
# Speaking 2
|
||||||
|
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||||
|
found_exercises_2 = [element for element in exercises if element.get('type') == 2]
|
||||||
|
# Check if any elements were found
|
||||||
|
if found_exercises_2:
|
||||||
|
exercise_2 = found_exercises_2[0]
|
||||||
app.app.logger.info('Creating video for speaking part 2')
|
app.app.logger.info('Creating video for speaking part 2')
|
||||||
sp2_result = create_video(exercises[1]["question"], random.choice(list(AvatarEnum)))
|
sp2_result = create_video(exercise_2["question"], random.choice(list(AvatarEnum)))
|
||||||
if sp2_result is not None:
|
if sp2_result is not None:
|
||||||
sound_file_path = VIDEO_FILES_PATH + sp2_result
|
sound_file_path = VIDEO_FILES_PATH + sp2_result
|
||||||
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp2_result
|
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp2_result
|
||||||
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
|
||||||
sp2_video_path = firebase_file_path
|
sp2_video_path = firebase_file_path
|
||||||
sp2_video_url = url
|
sp2_video_url = url
|
||||||
template["exercises"][1]["prompts"] = exercises[1]["prompts"]
|
template["exercises"][1]["prompts"] = exercise_2["prompts"]
|
||||||
template["exercises"][1]["text"] = exercises[1]["question"]
|
template["exercises"][1]["text"] = exercise_2["question"]
|
||||||
template["exercises"][1]["title"] = exercises[1]["topic"]
|
template["exercises"][1]["title"] = exercise_2["topic"]
|
||||||
template["exercises"][1]["video_url"] = sp2_video_url
|
template["exercises"][1]["video_url"] = sp2_video_url
|
||||||
template["exercises"][1]["video_path"] = sp2_video_path
|
template["exercises"][1]["video_path"] = sp2_video_path
|
||||||
else:
|
else:
|
||||||
app.app.logger.error("Failed to create video for part 2 question: " + exercises[1]["question"])
|
app.app.logger.error("Failed to create video for part 2 question: " + exercise_2["question"])
|
||||||
|
|
||||||
# Speaking 3
|
# Speaking 3
|
||||||
|
# Using list comprehension to find the element with the desired value in the 'type' field
|
||||||
|
found_exercises_3 = [element for element in exercises if element.get('type') == 3]
|
||||||
|
# Check if any elements were found
|
||||||
|
if found_exercises_3:
|
||||||
|
exercise_3 = found_exercises_3[0]
|
||||||
sp3_questions = []
|
sp3_questions = []
|
||||||
avatar = random.choice(list(AvatarEnum))
|
avatar = random.choice(list(AvatarEnum))
|
||||||
app.app.logger.info('Creating videos for speaking part 3')
|
app.app.logger.info('Creating videos for speaking part 3')
|
||||||
for question in exercises[2]["questions"]:
|
for question in exercise_3["questions"]:
|
||||||
result = create_video(question, avatar)
|
result = create_video(question, avatar)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
sound_file_path = VIDEO_FILES_PATH + result
|
sound_file_path = VIDEO_FILES_PATH + result
|
||||||
@@ -89,7 +104,14 @@ def create_videos_and_save_to_db(exercises, template, id):
|
|||||||
else:
|
else:
|
||||||
app.app.logger.error("Failed to create video for part 3 question: " + question)
|
app.app.logger.error("Failed to create video for part 3 question: " + question)
|
||||||
template["exercises"][2]["prompts"] = sp3_questions
|
template["exercises"][2]["prompts"] = sp3_questions
|
||||||
template["exercises"][2]["title"] = exercises[2]["topic"]
|
template["exercises"][2]["title"] = exercise_3["topic"]
|
||||||
|
|
||||||
|
if not found_exercises_3:
|
||||||
|
template["exercises"].pop(2)
|
||||||
|
if not found_exercises_2:
|
||||||
|
template["exercises"].pop(1)
|
||||||
|
if not found_exercises_1:
|
||||||
|
template["exercises"].pop(0)
|
||||||
|
|
||||||
save_to_db_with_id("speaking", template, id)
|
save_to_db_with_id("speaking", template, id)
|
||||||
app.app.logger.info('Saved speaking to DB with id ' + id + " : " + str(template))
|
app.app.logger.info('Saved speaking to DB with id ' + id + " : " + str(template))
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from helper.constants import *
|
||||||
|
|
||||||
|
|
||||||
def getListeningTemplate():
|
def getListeningTemplate():
|
||||||
return {
|
return {
|
||||||
@@ -34,7 +36,7 @@ def getListeningTemplate():
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"isDiagnostic": False,
|
"isDiagnostic": False,
|
||||||
"minTimer": 30,
|
"minTimer": LISTENING_MIN_TIMER_DEFAULT,
|
||||||
"module": "listening"
|
"module": "listening"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1180,7 +1182,7 @@ def getSpeakingTemplate():
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"isDiagnostic": False,
|
"isDiagnostic": False,
|
||||||
"minTimer": 14,
|
"minTimer": SPEAKING_MIN_TIMER_DEFAULT,
|
||||||
"module": "speaking"
|
"module": "speaking"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1242,7 +1244,7 @@ def getWritingTemplate():
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"isDiagnostic": False,
|
"isDiagnostic": False,
|
||||||
"minTimer": 60,
|
"minTimer": WRITING_MIN_TIMER_DEFAULT,
|
||||||
"module": "writing",
|
"module": "writing",
|
||||||
"type": "general"
|
"type": "general"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user