Writing improvements.

This commit is contained in:
Cristiano Ferreira
2024-07-26 23:33:42 +01:00
parent 19f204d74d
commit 3a7bb7764f

222
app.py
View File

@@ -1,4 +1,3 @@
import random
import threading import threading
from functools import reduce from functools import reduce
@@ -12,11 +11,11 @@ from helper.exam_variant import ExamVariant
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
from helper.firebase_helper import * 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.heygen_api import create_video, create_videos_and_save_to_db
from helper.openai_interface import * from helper.openai_interface import *
from helper.question_templates import * from helper.question_templates import *
from helper.speech_to_text_helper import * from helper.speech_to_text_helper import *
from helper.gpt_zero import GPTZero
from heygen.AvatarEnum import AvatarEnum from heygen.AvatarEnum import AvatarEnum
load_dotenv() load_dotenv()
@@ -226,22 +225,22 @@ def grade_writing_task_1():
'comment': "The answer does not contain enough english words.", 'comment': "The answer does not contain enough english words.",
'overall': 0, 'overall': 0,
'task_response': { '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': { 'Task Achievement': {
"grade": 0.0, "grade": 0.0,
"comment": "" "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): 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.", 'comment': "The answer is insufficient and too small to be graded.",
'overall': 0, 'overall': 0,
'task_response': { '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': { 'Task Achievement': {
"grade": 0.0, "grade": 0.0,
"comment": "" "comment": ""
} },
'Coherence and Cohesion': {
"grade": 0.0,
"comment": ""
},
'Lexical Resource': {
"grade": 0.0,
"comment": ""
},
'Grammatical Range and Accuracy': {
"grade": 0.0,
"comment": ""
}
} }
} }
else: else:
@@ -272,21 +271,21 @@ def grade_writing_task_1():
"comment": "comment about student's response quality", "comment": "comment about student's response quality",
"overall": 0.0, "overall": 0.0,
"task_response": { "task_response": {
"Task Achievement": {
"grade": 0.0,
"comment": "comment about Task Achievement of the student's response"
},
"Coherence and Cohesion": { "Coherence and Cohesion": {
"grade": 0.0, "grade": 0.0,
"comment": "comment about Coherence and Cohesion of the student's response" "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": { "Lexical Resource": {
"grade": 0.0, "grade": 0.0,
"comment": "comment about Lexical Resource of the student's response" "comment": "comment about Lexical Resource of the student's response"
}, },
"Task Achievement": { "Grammatical Range and Accuracy": {
"grade": 0.0, "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 = [ messages = [
{ {
"role": "system", "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", "role": "user",
@@ -343,19 +343,26 @@ def get_writing_task_1_general_question():
'of ' + difficulty + 'difficulty and does not contain ' 'of ' + difficulty + 'difficulty and does not contain '
'forbidden subjects in muslim ' 'forbidden subjects in muslim '
'countries.') '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) token_count = count_total_tokens(messages)
response = make_openai_call(GPT_3_5_TURBO, messages, token_count, "prompt", response = make_openai_call(GPT_3_5_TURBO, messages, token_count, "prompt",
GEN_QUESTION_TEMPERATURE) GEN_QUESTION_TEMPERATURE)
return { return {
"question": response["prompt"].strip(), "question": add_newline_before_hyphen(response["prompt"].strip()),
"difficulty": difficulty, "difficulty": difficulty,
"topic": topic "topic": topic
} }
except Exception as e: except Exception as e:
return str(e) return str(e)
def add_newline_before_hyphen(s):
return s.replace(" -", "\n-")
@app.route('/writing_task2', methods=['POST']) @app.route('/writing_task2', methods=['POST'])
@jwt_required() @jwt_required()
@@ -369,22 +376,22 @@ def grade_writing_task_2():
'comment': "The answer does not contain enough english words.", 'comment': "The answer does not contain enough english words.",
'overall': 0, 'overall': 0,
'task_response': { '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': { 'Task Achievement': {
"grade": 0.0, "grade": 0.0,
"comment": "" "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): 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.", 'comment': "The answer is insufficient and too small to be graded.",
'overall': 0, 'overall': 0,
'task_response': { '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': { 'Task Achievement': {
"grade": 0.0, "grade": 0.0,
"comment": "" "comment": ""
} },
'Coherence and Cohesion': {
"grade": 0.0,
"comment": ""
},
'Lexical Resource': {
"grade": 0.0,
"comment": ""
},
'Grammatical Range and Accuracy': {
"grade": 0.0,
"comment": ""
}
} }
} }
else: else:
@@ -415,21 +422,21 @@ def grade_writing_task_2():
"comment": "comment about student's response quality", "comment": "comment about student's response quality",
"overall": 0.0, "overall": 0.0,
"task_response": { "task_response": {
"Task Achievement": {
"grade": 0.0,
"comment": "comment about Task Achievement of the student's response"
},
"Coherence and Cohesion": { "Coherence and Cohesion": {
"grade": 0.0, "grade": 0.0,
"comment": "comment about Coherence and Cohesion of the student's response" "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": { "Lexical Resource": {
"grade": 0.0, "grade": 0.0,
"comment": "comment about Lexical Resource of the student's response" "comment": "comment about Lexical Resource of the student's response"
}, },
"Task Achievement": { "Grammatical Range and Accuracy": {
"grade": 0.0, "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 = [ messages = [
{ {
"role": "system", "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", "role": "user",
@@ -493,8 +501,12 @@ def get_writing_task_2_general_question():
"content": ( "content": (
'Craft a comprehensive question of ' + difficulty + 'difficulty like the ones for IELTS Writing Task 2 General Training that directs the candidate ' '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 + '". ' '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 ' 'The candidate should be asked to discuss the strengths and weaknesses of both viewpoints.')
'examples, and present a well-rounded argument before concluding with their personal opinion on the subject.') },
{
"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) token_count = count_total_tokens(messages)
@@ -708,16 +720,16 @@ def get_speaking_task_1_question():
"role": "user", "role": "user",
"content": ( "content": (
'Craft 5 simple questions of easy 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 ' 'that encourages candidates to delve deeply into '
'personal experiences, preferences, or insights on the topic ' 'personal experiences, preferences, or insights on the topic '
'of "' + first_topic + '" and the topic of "' + second_topic + '". Instruct the candidate ' 'of "' + first_topic + '" and the topic of "' + second_topic + '". Instruct the candidate '
'to offer not only detailed ' 'to offer not only detailed '
'descriptions but also provide ' 'descriptions but also provide '
'nuanced explanations, examples, ' 'nuanced explanations, examples, '
'or anecdotes to enrich their response. ' 'or anecdotes to enrich their response. '
'Make sure that the generated question ' 'Make sure that the generated question '
'does not contain forbidden subjects in ' 'does not contain forbidden subjects in '
'muslim countries.') 'muslim countries.')
}, },
{ {
"role": "user", "role": "user",
@@ -900,13 +912,13 @@ def get_speaking_task_2_question():
'that encourages candidates to narrate a ' 'that encourages candidates to narrate a '
'personal experience or story related to the topic ' 'personal experience or story related to the topic '
'of "' + topic + '". Include 3 prompts that ' 'of "' + topic + '". Include 3 prompts that '
'guide the candidate to describe ' 'guide the candidate to describe '
'specific aspects of the experience, ' 'specific aspects of the experience, '
'such as details about the situation, ' 'such as details about the situation, '
'their actions, and the reasons it left a ' 'their actions, and the reasons it left a '
'lasting impression. Make sure that the ' 'lasting impression. Make sure that the '
'generated question does not contain ' 'generated question does not contain '
'forbidden subjects in muslim countries.') 'forbidden subjects in muslim countries.')
}, },
{ {
"role": "user", "role": "user",
@@ -952,8 +964,8 @@ def get_speaking_task_3_question():
"content": ( "content": (
'Formulate a set of 5 questions of hard difficulty for IELTS Speaking Part 3 that encourage candidates to engage in a ' '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 ' 'meaningful discussion on the topic of "' + topic + '". Provide inquiries, ensuring '
'they explore various aspects, perspectives, and implications related to the topic.' '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.') '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 return overall
@app.route('/speaking', methods=['POST']) @app.route('/speaking', methods=['POST'])
@jwt_required() @jwt_required()
def save_speaking(): def save_speaking():
@@ -1491,8 +1504,10 @@ def get_level_utas():
except Exception as e: except Exception as e:
return str(e) return str(e)
from enum import Enum from enum import Enum
class CustomLevelExerciseTypes(Enum): class CustomLevelExerciseTypes(Enum):
MULTIPLE_CHOICE_4 = "multiple_choice_4" MULTIPLE_CHOICE_4 = "multiple_choice_4"
MULTIPLE_CHOICE_BLANK_SPACE = "multiple_choice_blank_space" MULTIPLE_CHOICE_BLANK_SPACE = "multiple_choice_blank_space"
@@ -1500,6 +1515,7 @@ class CustomLevelExerciseTypes(Enum):
BLANK_SPACE_TEXT = "blank_space_text" BLANK_SPACE_TEXT = "blank_space_text"
READING_PASSAGE_UTAS = "reading_passage_utas" READING_PASSAGE_UTAS = "reading_passage_utas"
@app.route('/custom_level', methods=['GET']) @app.route('/custom_level', methods=['GET'])
@jwt_required() @jwt_required()
def get_custom_level(): def get_custom_level():
@@ -1523,7 +1539,8 @@ def get_custom_level():
response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice" response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice"
exercise_id = exercise_id + exercise_qty exercise_id = exercise_id + exercise_qty
elif exercise_type == CustomLevelExerciseTypes.MULTIPLE_CHOICE_BLANK_SPACE.value: 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" response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice"
exercise_id = exercise_id + exercise_qty exercise_id = exercise_id + exercise_qty
elif exercise_type == CustomLevelExerciseTypes.MULTIPLE_CHOICE_UNDERLINED.value: elif exercise_type == CustomLevelExerciseTypes.MULTIPLE_CHOICE_UNDERLINED.value:
@@ -1531,16 +1548,19 @@ def get_custom_level():
response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice" response["exercises"]["exercise_" + str(i)]["type"] = "multipleChoice"
exercise_id = exercise_id + exercise_qty exercise_id = exercise_id + exercise_qty
elif exercise_type == CustomLevelExerciseTypes.BLANK_SPACE_TEXT.value: 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" response["exercises"]["exercise_" + str(i)]["type"] = "blankSpaceText"
exercise_id = exercise_id + exercise_qty exercise_id = exercise_id + exercise_qty
elif exercise_type == CustomLevelExerciseTypes.READING_PASSAGE_UTAS.value: 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" response["exercises"]["exercise_" + str(i)]["type"] = "readingExercises"
exercise_id = exercise_id + exercise_qty exercise_id = exercise_id + exercise_qty
return response return response
@app.route('/fetch_tips', methods=['POST']) @app.route('/fetch_tips', methods=['POST'])
@jwt_required() @jwt_required()
def fetch_answer_tips(): def fetch_answer_tips():