Merge branch 'develop' of bitbucket.org:ecropdev/ielts-be into develop

This commit is contained in:
Tiago Ribeiro
2024-07-09 12:11:46 +01:00
3 changed files with 161 additions and 41 deletions

148
app.py
View File

@@ -53,7 +53,7 @@ def get_listening_section_1_question():
difficulty = request.args.get("difficulty", default=random.choice(difficulties))
if (len(req_exercises) == 0):
req_exercises = random.sample(LISTENING_EXERCISE_TYPES, 1)
req_exercises = random.sample(LISTENING_1_EXERCISE_TYPES, 1)
number_of_exercises_q = divide_number_into_parts(TOTAL_LISTENING_SECTION_1_EXERCISES, len(req_exercises))
@@ -62,7 +62,8 @@ def get_listening_section_1_question():
app.logger.info("Generated conversation: " + str(processed_conversation))
start_id = 1
exercises = generate_listening_conversation_exercises(parse_conversation(processed_conversation), req_exercises,
exercises = generate_listening_conversation_exercises(parse_conversation(processed_conversation),
req_exercises,
number_of_exercises_q,
start_id, difficulty)
return {
@@ -85,7 +86,7 @@ def get_listening_section_2_question():
difficulty = request.args.get("difficulty", default=random.choice(difficulties))
if (len(req_exercises) == 0):
req_exercises = random.sample(LISTENING_EXERCISE_TYPES, 2)
req_exercises = random.sample(LISTENING_2_EXERCISE_TYPES, 2)
number_of_exercises_q = divide_number_into_parts(TOTAL_LISTENING_SECTION_2_EXERCISES, len(req_exercises))
@@ -115,7 +116,7 @@ def get_listening_section_3_question():
difficulty = request.args.get("difficulty", default=random.choice(difficulties))
if (len(req_exercises) == 0):
req_exercises = random.sample(LISTENING_EXERCISE_TYPES, 1)
req_exercises = random.sample(LISTENING_3_EXERCISE_TYPES, 1)
number_of_exercises_q = divide_number_into_parts(TOTAL_LISTENING_SECTION_3_EXERCISES, len(req_exercises))
@@ -591,7 +592,7 @@ def grade_speaking_task_1():
@app.route('/speaking_task_1', methods=['GET'])
@jwt_required()
def get_speaking_task_1_question():
difficulty = request.args.get("difficulty", default=random.choice(difficulties))
difficulty = request.args.get("difficulty", default="easy")
first_topic = request.args.get("first_topic", default=random.choice(mti_topics))
second_topic = request.args.get("second_topic", default=random.choice(mti_topics))
@@ -599,7 +600,7 @@ def get_speaking_task_1_question():
"first_topic": "topic 1",
"second_topic": "topic 2",
"questions": [
"Introductory question, should start with a greeting and introduce a question about the first topic.",
"Introductory question, should start with a greeting and introduce a question about the first topic, starting the topic with 'Let's talk about x' and then the question.",
"Follow up question about the first topic",
"Follow up question about the first topic",
"Question about second topic",
@@ -617,7 +618,7 @@ def get_speaking_task_1_question():
{
"role": "user",
"content": (
'Craft 5 thought-provoking questions of ' + difficulty + ' difficulty for IELTS Speaking Part 1 '
'Craft 5 simple questions of easy difficulty for IELTS Speaking Part 1 '
'that encourages candidates to delve deeply into '
'personal experiences, preferences, or insights on the topic '
'of "' + first_topic + '" and the topic of "' + second_topic + '". Instruct the candidate '
@@ -813,7 +814,7 @@ def get_speaking_task_2_question():
'Create a question of medium difficulty for IELTS Speaking Part 2 '
'that encourages candidates to narrate a '
'personal experience or story related to the topic '
'of "' + random.choice(mti_topics) + '". Include 3 prompts that '
'of "' + topic + '". Include 3 prompts that '
'guide the candidate to describe '
'specific aspects of the experience, '
'such as details about the situation, '
@@ -847,7 +848,7 @@ def get_speaking_task_3_question():
json_format = {
"topic": "topic",
"questions": [
"Introductory question, should start with a greeting and introduce a question about the topic.",
"Introductory question about the topic.",
"Follow up question about the topic",
"Follow up question about the topic",
"Follow up question about the topic",
@@ -865,8 +866,7 @@ def get_speaking_task_3_question():
"role": "user",
"content": (
'Formulate a set of 5 questions of hard difficulty for IELTS Speaking Part 3 that encourage candidates to engage in a '
'meaningful discussion on the topic of "' + random.choice(
mti_topics) + '". Provide inquiries, ensuring '
'meaningful discussion on the topic of "' + topic + '". Provide inquiries, ensuring '
'they explore various aspects, perspectives, and implications related to the topic.'
'Make sure that the generated question does not contain forbidden subjects in muslim countries.')
@@ -1080,21 +1080,93 @@ def save_speaking():
return str(e)
@app.route("/speaking/generate_speaking_video", methods=['POST'])
@app.route("/speaking/generate_video_1", methods=['POST'])
@jwt_required()
def generate_speaking_video():
def generate_video_1():
try:
data = request.get_json()
sp3_questions = []
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
request_id = str(uuid.uuid4())
logging.info("POST - generate_video_1 - Received request to generate video 1. "
"Use this id to track the logs: " + str(request_id) + " - Request data: " + str(
request.get_json()))
logging.info("POST - generate_video_1 - " + str(request_id) + " - Creating videos for speaking part 1.")
for question in data["questions"]:
logging.info("POST - generate_video_1 - " + str(request_id) + " - Creating video for question: " + question)
result = create_video(question, avatar)
logging.info("POST - generate_video_1 - " + str(request_id) + " - Video created: " + result)
if result is not None:
sound_file_path = VIDEO_FILES_PATH + result
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + result
logging.info(
"POST - generate_video_1 - " + str(
request_id) + " - Uploading video to firebase: " + firebase_file_path)
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
logging.info(
"POST - generate_video_1 - " + str(
request_id) + " - Uploaded video to firebase: " + url)
video = {
"text": question,
"video_path": firebase_file_path,
"video_url": url
}
sp3_questions.append(video)
else:
logging.error("POST - generate_video_1 - " + str(
request_id) + " - Failed to create video for part 1 question: " + question)
response = {
"prompts": sp3_questions,
"first_title": data["first_topic"],
"second_title": data["second_topic"],
"type": "interactiveSpeaking",
"id": uuid.uuid4()
}
logging.info(
"POST - generate_video_1 - " + str(
request_id) + " - Finished creating videos for speaking part 1: " + str(response))
return response
except Exception as e:
return str(e)
@app.route("/speaking/generate_video_2", methods=['POST'])
@jwt_required()
def generate_video_2():
try:
data = request.get_json()
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
prompts = data.get("prompts", [])
question = data.get("question")
if len(prompts) > 0:
question = question + " In your answer you should consider: " + " ".join(prompts)
sp1_result = create_video(question, avatar)
if sp1_result is not None:
sound_file_path = VIDEO_FILES_PATH + sp1_result
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + sp1_result
suffix = data.get("suffix", "")
# Removed as the examiner should not say what is on the card.
# question = question + " In your answer you should consider: " + " ".join(prompts) + suffix
question = question + "\nYou have 1 minute to take notes."
request_id = str(uuid.uuid4())
logging.info("POST - generate_video_2 - Received request to generate video 2. "
"Use this id to track the logs: " + str(request_id) + " - Request data: " + str(
request.get_json()))
logging.info("POST - generate_video_2 - " + str(request_id) + " - Creating video for speaking part 2.")
logging.info("POST - generate_video_2 - " + str(request_id) + " - Creating video for question: " + question)
result = create_video(question, avatar)
logging.info("POST - generate_video_2 - " + str(request_id) + " - Video created: " + result)
if result is not None:
sound_file_path = VIDEO_FILES_PATH + result
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + result
logging.info(
"POST - generate_video_2 - " + str(
request_id) + " - Uploading video to firebase: " + firebase_file_path)
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
logging.info(
"POST - generate_video_2 - " + str(
request_id) + " - Uploaded video to firebase: " + url)
sp1_video_path = firebase_file_path
sp1_video_url = url
@@ -1105,31 +1177,47 @@ def generate_speaking_video():
"video_url": sp1_video_url,
"video_path": sp1_video_path,
"type": "speaking",
"id": uuid.uuid4()
"id": uuid.uuid4(),
"suffix": suffix
}
else:
app.logger.error("Failed to create video for part 1 question: " + data["question"])
return str("Failed to create video for part 1 question: " + data["question"])
logging.error("POST - generate_video_2 - " + str(
request_id) + " - Failed to create video for part 2 question: " + question)
return str("Failed to create video for part 2 question: " + data["question"])
except Exception as e:
return str(e)
@app.route("/speaking/generate_interactive_video", methods=['POST'])
@app.route("/speaking/generate_video_3", methods=['POST'])
@jwt_required()
def generate_interactive_video():
def generate_video_3():
try:
data = request.get_json()
sp3_questions = []
avatar = data.get("avatar", random.choice(list(AvatarEnum)).value)
app.logger.info('Creating videos for speaking part 3')
request_id = str(uuid.uuid4())
logging.info("POST - generate_video_3 - Received request to generate video 3. "
"Use this id to track the logs: " + str(request_id) + " - Request data: " + str(
request.get_json()))
logging.info("POST - generate_video_3 - " + str(request_id) + " - Creating videos for speaking part 3.")
for question in data["questions"]:
logging.info("POST - generate_video_3 - " + str(request_id) + " - Creating video for question: " + question)
result = create_video(question, avatar)
logging.info("POST - generate_video_3 - " + str(request_id) + " - Video created: " + result)
if result is not None:
sound_file_path = VIDEO_FILES_PATH + result
firebase_file_path = FIREBASE_SPEAKING_VIDEO_FILES_PATH + result
logging.info(
"POST - generate_video_3 - " + str(
request_id) + " - Uploading video to firebase: " + firebase_file_path)
url = upload_file_firebase_get_url(FIREBASE_BUCKET, firebase_file_path, sound_file_path)
logging.info(
"POST - generate_video_3 - " + str(
request_id) + " - Uploaded video to firebase: " + url)
video = {
"text": question,
"video_path": firebase_file_path,
@@ -1137,14 +1225,19 @@ def generate_interactive_video():
}
sp3_questions.append(video)
else:
app.app.logger.error("Failed to create video for part 3 question: " + question)
logging.error("POST - generate_video_3 - " + str(
request_id) + " - Failed to create video for part 3 question: " + question)
return {
response = {
"prompts": sp3_questions,
"title": data["topic"],
"type": "interactiveSpeaking",
"id": uuid.uuid4()
}
logging.info(
"POST - generate_video_3 - " + str(
request_id) + " - Finished creating videos for speaking part 3: " + str(response))
return response
except Exception as e:
return str(e)
@@ -1203,6 +1296,7 @@ def get_level_exam():
except Exception as e:
return str(e)
@app.route('/level_utas', methods=['GET'])
@jwt_required()
def get_level_utas():

View File

@@ -19,6 +19,11 @@ GEN_TEXT_FIELDS = ['title']
LISTENING_GEN_FIELDS = ['transcript', 'exercise']
READING_EXERCISE_TYPES = ['fillBlanks', 'writeBlanks', 'trueFalse', 'paragraphMatch']
LISTENING_EXERCISE_TYPES = ['multipleChoice', 'writeBlanksQuestions', 'writeBlanksFill', 'writeBlanksForm']
LISTENING_1_EXERCISE_TYPES = ['multipleChoice', 'writeBlanksQuestions', 'writeBlanksFill', 'writeBlanksFill',
'writeBlanksForm', 'writeBlanksForm', 'writeBlanksForm', 'writeBlanksForm']
LISTENING_2_EXERCISE_TYPES = ['multipleChoice', 'writeBlanksQuestions']
LISTENING_3_EXERCISE_TYPES = ['multipleChoice3Options', 'writeBlanksQuestions']
LISTENING_4_EXERCISE_TYPES = ['multipleChoice', 'writeBlanksQuestions', 'writeBlanksFill', 'writeBlanksForm']
TOTAL_READING_PASSAGE_1_EXERCISES = 13
TOTAL_READING_PASSAGE_2_EXERCISES = 13

View File

@@ -283,6 +283,16 @@ def generate_listening_1_conversation(topic: str):
'Make sure that the generated conversation does not contain forbidden subjects in '
'muslim countries.')
},
{
"role": "user",
"content": 'Try to have misleading discourse (refer multiple dates, multiple colors and etc).'
},
{
"role": "user",
"content": 'Try to have spelling of names (cities, people, etc)'
}
]
token_count = count_total_tokens(messages)
@@ -400,7 +410,7 @@ def generate_listening_4_monologue(topic: str):
{
"role": "user",
"content": (
'Generate a comprehensive monologue on the academic subject '
'Generate a comprehensive and complex monologue on the academic subject '
'of: "' + topic + '". Make sure that the generated monologue does not contain forbidden subjects in '
'muslim countries.')
@@ -467,7 +477,12 @@ def generate_listening_conversation_exercises(conversation: str, req_exercises:
if req_exercise == "multipleChoice":
question = gen_multiple_choice_exercise_listening_conversation(conversation, number_of_exercises, start_id,
difficulty)
difficulty, 4)
exercises.append(question)
print("Added multiple choice: " + str(question))
elif req_exercise == "multipleChoice3Options":
question = gen_multiple_choice_exercise_listening_conversation(conversation, number_of_exercises, start_id,
difficulty, 3)
exercises.append(question)
print("Added multiple choice: " + str(question))
elif req_exercise == "writeBlanksQuestions":
@@ -723,7 +738,7 @@ def assign_letters_to_paragraphs(paragraphs):
return result
def gen_multiple_choice_exercise_listening_conversation(text: str, quantity: int, start_id, difficulty):
def gen_multiple_choice_exercise_listening_conversation(text: str, quantity: int, start_id, difficulty, n_options=4):
messages = [
{
"role": "system",
@@ -737,7 +752,7 @@ def gen_multiple_choice_exercise_listening_conversation(text: str, quantity: int
{
"role": "user",
"content": (
'Generate ' + str(quantity) + ' ' + difficulty + ' difficulty multiple choice questions of 4 options '
'Generate ' + str(quantity) + ' ' + difficulty + ' difficulty multiple choice questions of ' + str(n_options) + ' options '
'of for this conversation:\n"' + text + '"')
}
@@ -753,7 +768,7 @@ def gen_multiple_choice_exercise_listening_conversation(text: str, quantity: int
}
def gen_multiple_choice_exercise_listening_monologue(text: str, quantity: int, start_id, difficulty):
def gen_multiple_choice_exercise_listening_monologue(text: str, quantity: int, start_id, difficulty, n_options=4):
messages = [
{
"role": "system",
@@ -768,7 +783,7 @@ def gen_multiple_choice_exercise_listening_monologue(text: str, quantity: int, s
"role": "user",
"content": (
'Generate ' + str(
quantity) + ' ' + difficulty + ' difficulty multiple choice questions of 4 options '
quantity) + ' ' + difficulty + ' difficulty multiple choice questions of ' + str(n_options) + ' options '
'of for this monologue:\n"' + text + '"')
}
@@ -951,13 +966,19 @@ def gen_write_blanks_form_exercise_listening_conversation(text: str, quantity: i
"role": "system",
"content": (
'You are a helpful assistant designed to output JSON on this format: '
'{"form": ["key: value", "key2: value"]}')
'{"form": ["key": "value", "key2": "value"]}')
},
{
"role": "user",
"content": (
'Generate a form with ' + str(
quantity) + ' ' + difficulty + ' difficulty key-value pairs about this conversation:\n"' + text + '"')
quantity) + ' entries with information about this conversation:\n"' + text + '"')
},
{
"role": "user",
"content": 'It must be a form and not questions. '
'Example: {"form": ["Color of car": "blue", "Brand of car": "toyota"]}'
}
]