diff --git a/app.py b/app.py index 13e638e..a0b26be 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,3 @@ -import random import threading from functools import reduce @@ -12,11 +11,11 @@ from helper.exam_variant import ExamVariant from helper.exercises import * from helper.file_helper import delete_files_older_than_one_day from helper.firebase_helper import * +from helper.gpt_zero import GPTZero from helper.heygen_api import create_video, create_videos_and_save_to_db from helper.openai_interface import * from helper.question_templates import * from helper.speech_to_text_helper import * -from helper.gpt_zero import GPTZero from heygen.AvatarEnum import AvatarEnum load_dotenv() @@ -226,22 +225,22 @@ def grade_writing_task_1(): 'comment': "The answer does not contain enough english words.", 'overall': 0, 'task_response': { - 'Coherence and Cohesion': { - "grade": 0.0, - "comment": "" - }, - 'Grammatical Range and Accuracy': { - "grade": 0.0, - "comment": "" - }, - 'Lexical Resource': { - "grade": 0.0, - "comment": "" - }, 'Task Achievement': { - "grade": 0.0, - "comment": "" - } + "grade": 0.0, + "comment": "" + }, + 'Coherence and Cohesion': { + "grade": 0.0, + "comment": "" + }, + 'Lexical Resource': { + "grade": 0.0, + "comment": "" + }, + 'Grammatical Range and Accuracy': { + "grade": 0.0, + "comment": "" + } } } elif not has_x_words(answer, 100): @@ -249,22 +248,22 @@ def grade_writing_task_1(): 'comment': "The answer is insufficient and too small to be graded.", 'overall': 0, 'task_response': { - 'Coherence and Cohesion': { - "grade": 0.0, - "comment": "" - }, - 'Grammatical Range and Accuracy': { - "grade": 0.0, - "comment": "" - }, - 'Lexical Resource': { - "grade": 0.0, - "comment": "" - }, 'Task Achievement': { - "grade": 0.0, - "comment": "" - } + "grade": 0.0, + "comment": "" + }, + 'Coherence and Cohesion': { + "grade": 0.0, + "comment": "" + }, + 'Lexical Resource': { + "grade": 0.0, + "comment": "" + }, + 'Grammatical Range and Accuracy': { + "grade": 0.0, + "comment": "" + } } } else: @@ -272,21 +271,21 @@ def grade_writing_task_1(): "comment": "comment about student's response quality", "overall": 0.0, "task_response": { + "Task Achievement": { + "grade": 0.0, + "comment": "comment about Task Achievement of the student's response" + }, "Coherence and Cohesion": { "grade": 0.0, "comment": "comment about Coherence and Cohesion of the student's response" }, - "Grammatical Range and Accuracy": { - "grade": 0.0, - "comment": "comment about Grammatical Range and Accuracy of the student's response" - }, "Lexical Resource": { "grade": 0.0, "comment": "comment about Lexical Resource of the student's response" }, - "Task Achievement": { + "Grammatical Range and Accuracy": { "grade": 0.0, - "comment": "comment about Task Achievement of the student's response" + "comment": "comment about Grammatical Range and Accuracy of the student's response" } } } @@ -294,7 +293,8 @@ def grade_writing_task_1(): messages = [ { "role": "system", - "content": ('You are a helpful assistant designed to output JSON on this format: ' + str(json_format)) + "content": ('You are a helpful assistant designed to output JSON on this format: ' + str( + json_format)) }, { "role": "user", @@ -343,19 +343,26 @@ def get_writing_task_1_general_question(): 'of ' + difficulty + 'difficulty and does not contain ' 'forbidden subjects in muslim ' 'countries.') + }, + { + "role": "user", + "content": 'The prompt should end with "In the letter you should" followed by 3 bullet points of what ' + 'the answer should include.' } ] token_count = count_total_tokens(messages) response = make_openai_call(GPT_3_5_TURBO, messages, token_count, "prompt", GEN_QUESTION_TEMPERATURE) return { - "question": response["prompt"].strip(), + "question": add_newline_before_hyphen(response["prompt"].strip()), "difficulty": difficulty, "topic": topic } except Exception as e: return str(e) +def add_newline_before_hyphen(s): + return s.replace(" -", "\n-") @app.route('/writing_task2', methods=['POST']) @jwt_required() @@ -369,22 +376,22 @@ def grade_writing_task_2(): 'comment': "The answer does not contain enough english words.", 'overall': 0, 'task_response': { - 'Coherence and Cohesion': { - "grade": 0.0, - "comment": "" - }, - 'Grammatical Range and Accuracy': { - "grade": 0.0, - "comment": "" - }, - 'Lexical Resource': { - "grade": 0.0, - "comment": "" - }, 'Task Achievement': { - "grade": 0.0, - "comment": "" - } + "grade": 0.0, + "comment": "" + }, + 'Coherence and Cohesion': { + "grade": 0.0, + "comment": "" + }, + 'Lexical Resource': { + "grade": 0.0, + "comment": "" + }, + 'Grammatical Range and Accuracy': { + "grade": 0.0, + "comment": "" + } } } elif not has_x_words(answer, 180): @@ -392,22 +399,22 @@ def grade_writing_task_2(): 'comment': "The answer is insufficient and too small to be graded.", 'overall': 0, 'task_response': { - 'Coherence and Cohesion': { - "grade": 0.0, - "comment": "" - }, - 'Grammatical Range and Accuracy': { - "grade": 0.0, - "comment": "" - }, - 'Lexical Resource': { - "grade": 0.0, - "comment": "" - }, 'Task Achievement': { - "grade": 0.0, - "comment": "" - } + "grade": 0.0, + "comment": "" + }, + 'Coherence and Cohesion': { + "grade": 0.0, + "comment": "" + }, + 'Lexical Resource': { + "grade": 0.0, + "comment": "" + }, + 'Grammatical Range and Accuracy': { + "grade": 0.0, + "comment": "" + } } } else: @@ -415,21 +422,21 @@ def grade_writing_task_2(): "comment": "comment about student's response quality", "overall": 0.0, "task_response": { + "Task Achievement": { + "grade": 0.0, + "comment": "comment about Task Achievement of the student's response" + }, "Coherence and Cohesion": { "grade": 0.0, "comment": "comment about Coherence and Cohesion of the student's response" }, - "Grammatical Range and Accuracy": { - "grade": 0.0, - "comment": "comment about Grammatical Range and Accuracy of the student's response" - }, "Lexical Resource": { "grade": 0.0, "comment": "comment about Lexical Resource of the student's response" }, - "Task Achievement": { + "Grammatical Range and Accuracy": { "grade": 0.0, - "comment": "comment about Task Achievement of the student's response" + "comment": "comment about Grammatical Range and Accuracy of the student's response" } } } @@ -437,7 +444,8 @@ def grade_writing_task_2(): messages = [ { "role": "system", - "content": ('You are a helpful assistant designed to output JSON on this format: ' + str(json_format)) + "content": ('You are a helpful assistant designed to output JSON on this format: ' + str( + json_format)) }, { "role": "user", @@ -493,8 +501,12 @@ def get_writing_task_2_general_question(): "content": ( 'Craft a comprehensive question of ' + difficulty + 'difficulty like the ones for IELTS Writing Task 2 General Training that directs the candidate ' 'to delve into an in-depth analysis of contrasting perspectives on the topic of "' + topic + '". ' - 'The candidate should be asked to discuss the strengths and weaknesses of both viewpoints, provide evidence or ' - 'examples, and present a well-rounded argument before concluding with their personal opinion on the subject.') + 'The candidate should be asked to discuss the strengths and weaknesses of both viewpoints.') + }, + { + "role": "user", + "content": 'The question should lead to an answer with either "theories", "complicated information" or ' + 'be "very descriptive" on the topic.' } ] token_count = count_total_tokens(messages) @@ -708,16 +720,16 @@ def get_speaking_task_1_question(): "role": "user", "content": ( '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 ' - 'to offer not only detailed ' - 'descriptions but also provide ' - 'nuanced explanations, examples, ' - 'or anecdotes to enrich their response. ' - 'Make sure that the generated question ' - 'does not contain forbidden subjects in ' - 'muslim countries.') + '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 ' + 'to offer not only detailed ' + 'descriptions but also provide ' + 'nuanced explanations, examples, ' + 'or anecdotes to enrich their response. ' + 'Make sure that the generated question ' + 'does not contain forbidden subjects in ' + 'muslim countries.') }, { "role": "user", @@ -900,13 +912,13 @@ def get_speaking_task_2_question(): 'that encourages candidates to narrate a ' 'personal experience or story related to the topic ' 'of "' + topic + '". Include 3 prompts that ' - 'guide the candidate to describe ' - 'specific aspects of the experience, ' - 'such as details about the situation, ' - 'their actions, and the reasons it left a ' - 'lasting impression. Make sure that the ' - 'generated question does not contain ' - 'forbidden subjects in muslim countries.') + 'guide the candidate to describe ' + 'specific aspects of the experience, ' + 'such as details about the situation, ' + 'their actions, and the reasons it left a ' + 'lasting impression. Make sure that the ' + 'generated question does not contain ' + 'forbidden subjects in muslim countries.') }, { "role": "user", @@ -952,8 +964,8 @@ def get_speaking_task_3_question(): "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 "' + 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.') + '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.') } ] @@ -1141,6 +1153,7 @@ def fix_speaking_overall(overall: float, task_response: dict): return overall + @app.route('/speaking', methods=['POST']) @jwt_required() def save_speaking(): @@ -1491,8 +1504,10 @@ def get_level_utas(): except Exception as e: return str(e) + from enum import Enum + class CustomLevelExerciseTypes(Enum): MULTIPLE_CHOICE_4 = "multiple_choice_4" MULTIPLE_CHOICE_BLANK_SPACE = "multiple_choice_blank_space" @@ -1500,6 +1515,7 @@ class CustomLevelExerciseTypes(Enum): BLANK_SPACE_TEXT = "blank_space_text" READING_PASSAGE_UTAS = "reading_passage_utas" + @app.route('/custom_level', methods=['GET']) @jwt_required() def get_custom_level(): @@ -1523,7 +1539,8 @@ def get_custom_level(): response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice" exercise_id = exercise_id + exercise_qty elif exercise_type == CustomLevelExerciseTypes.MULTIPLE_CHOICE_BLANK_SPACE.value: - response["exercises"]["exercise_" + str(i)] = gen_multiple_choice_blank_space_utas(exercise_qty, exercise_id) + response["exercises"]["exercise_" + str(i)] = gen_multiple_choice_blank_space_utas(exercise_qty, + exercise_id) response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice" exercise_id = exercise_id + exercise_qty elif exercise_type == CustomLevelExerciseTypes.MULTIPLE_CHOICE_UNDERLINED.value: @@ -1531,16 +1548,19 @@ def get_custom_level(): response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice" exercise_id = exercise_id + exercise_qty elif exercise_type == CustomLevelExerciseTypes.BLANK_SPACE_TEXT.value: - response["exercises"]["exercise_" + str(i)] = gen_blank_space_text_utas(exercise_qty, exercise_id, exercise_text_size) + response["exercises"]["exercise_" + str(i)] = gen_blank_space_text_utas(exercise_qty, exercise_id, + exercise_text_size) response["exercises"]["exercise_" + str(i)]["type"] = "blankSpaceText" exercise_id = exercise_id + exercise_qty elif exercise_type == CustomLevelExerciseTypes.READING_PASSAGE_UTAS.value: - response["exercises"]["exercise_" + str(i)] = gen_reading_passage_utas(exercise_id, exercise_sa_qty, exercise_mc_qty, exercise_topic) + response["exercises"]["exercise_" + str(i)] = gen_reading_passage_utas(exercise_id, exercise_sa_qty, + exercise_mc_qty, exercise_topic) response["exercises"]["exercise_" + str(i)]["type"] = "readingExercises" exercise_id = exercise_id + exercise_qty return response + @app.route('/fetch_tips', methods=['POST']) @jwt_required() def fetch_answer_tips():