ENCOA-311
This commit is contained in:
@@ -13,6 +13,7 @@ from ielts_be.services import (
|
||||
ILevelService, ILLMService, IReadingService,
|
||||
IWritingService, IListeningService, ISpeakingService
|
||||
)
|
||||
from ielts_be.utils import pick_difficulty
|
||||
from .exercises import MultipleChoice, BlankSpace, PassageUtas, FillBlanks
|
||||
from .full_exams import CustomLevelModule, LevelUtas
|
||||
from .upload import UploadLevelModule
|
||||
@@ -50,19 +51,22 @@ class LevelService(ILevelService):
|
||||
async def upload_level(self, upload: UploadFile, solutions: Optional[UploadFile] = None) -> Dict:
|
||||
return await self._upload_module.generate_level_from_file(upload, solutions)
|
||||
|
||||
async def _generate_exercise(self, req_exercise, start_id):
|
||||
async def _generate_exercise(self, req_exercise, start_id, difficulties):
|
||||
difficulty = pick_difficulty(req_exercise.difficulty, difficulties)
|
||||
if req_exercise.type == "mcBlank":
|
||||
questions = await self._mc.gen_multiple_choice("blank_space", req_exercise.quantity, start_id)
|
||||
questions = await self._mc.gen_multiple_choice("blank_space", req_exercise.quantity, difficulty, start_id)
|
||||
questions["variant"] = "mcBlank"
|
||||
questions["type"] = "multipleChoice"
|
||||
questions["prompt"] = "Choose the correct word or group of words that completes the sentences."
|
||||
questions["difficulty"] = difficulty
|
||||
return questions
|
||||
|
||||
elif req_exercise.type == "mcUnderline":
|
||||
questions = await self._mc.gen_multiple_choice("underline", req_exercise.quantity, start_id)
|
||||
questions = await self._mc.gen_multiple_choice("underline", req_exercise.quantity, difficulty, start_id)
|
||||
questions["variant"] = "mcUnderline"
|
||||
questions["type"] = "multipleChoice"
|
||||
questions["prompt"] = "Choose the underlined word or group of words that is not correct."
|
||||
questions["difficulty"] = difficulty
|
||||
return questions
|
||||
|
||||
elif req_exercise.type == "passageUtas":
|
||||
@@ -70,21 +74,24 @@ class LevelService(ILevelService):
|
||||
exercise = await self._passage_utas.gen_reading_passage_utas(
|
||||
start_id,
|
||||
req_exercise.quantity,
|
||||
difficulty,
|
||||
topic,
|
||||
req_exercise.text_size
|
||||
)
|
||||
exercise["prompt"] = "Read the text and answer the questions below."
|
||||
|
||||
exercise["difficulty"] = difficulty
|
||||
return exercise
|
||||
|
||||
elif req_exercise.type == "fillBlanksMC":
|
||||
exercise = await self._fill_blanks.gen_fill_blanks(
|
||||
start_id,
|
||||
req_exercise.quantity,
|
||||
difficulty,
|
||||
req_exercise.text_size,
|
||||
req_exercise.topic
|
||||
)
|
||||
exercise["prompt"] = "Read the text below and choose the correct word for each space."
|
||||
exercise["difficulty"] = difficulty
|
||||
return exercise
|
||||
|
||||
async def generate_exercises(self, dto: LevelExercisesDTO):
|
||||
@@ -95,7 +102,7 @@ class LevelService(ILevelService):
|
||||
current_id += req_exercise.quantity
|
||||
|
||||
tasks = [
|
||||
self._generate_exercise(req_exercise, start_id)
|
||||
self._generate_exercise(req_exercise, start_id, dto.difficulty)
|
||||
for req_exercise, start_id in zip(dto.exercises, start_ids)
|
||||
]
|
||||
questions = await gather(*tasks)
|
||||
@@ -105,10 +112,12 @@ class LevelService(ILevelService):
|
||||
|
||||
# Just here to support other modules that I don't know if they are supposed to still be used
|
||||
async def gen_multiple_choice(self, mc_variant: str, quantity: int, start_id: int = 1):
|
||||
return await self._mc.gen_multiple_choice(mc_variant, quantity, start_id)
|
||||
difficulty = random.choice(EducationalContent.DIFFICULTIES)
|
||||
return await self._mc.gen_multiple_choice(mc_variant, quantity, difficulty, start_id)
|
||||
|
||||
async def gen_reading_passage_utas(self, start_id, mc_quantity: int, topic=Optional[str]): # sa_quantity: int,
|
||||
return await self._passage_utas.gen_reading_passage_utas(start_id, mc_quantity, topic)
|
||||
difficulty = random.choice(EducationalContent.DIFFICULTIES)
|
||||
return await self._passage_utas.gen_reading_passage_utas(start_id, mc_quantity, difficulty, topic)
|
||||
|
||||
async def gen_blank_space_text_utas(self, quantity: int, start_id: int, size: int, topic: str):
|
||||
return await self._blank_space.gen_blank_space_text_utas(quantity, start_id, size, topic)
|
||||
|
||||
@@ -11,12 +11,10 @@ class FillBlanks:
|
||||
|
||||
|
||||
async def gen_fill_blanks(
|
||||
self, start_id: int, quantity: int, size: int = 300, topic=None
|
||||
self, start_id: int, quantity: int, difficulty: str, size: int = 300, topic=None
|
||||
):
|
||||
if not topic:
|
||||
topic = random.choice(EducationalContent.MTI_TOPICS)
|
||||
print(quantity)
|
||||
print(start_id)
|
||||
messages = [
|
||||
{
|
||||
"role": "system",
|
||||
@@ -34,8 +32,15 @@ class FillBlanks:
|
||||
'JSON object containing: the modified text, a solutions array with each word\'s correct '
|
||||
'letter (A-D), and a words array containing each id with four options where one is '
|
||||
'the original word (matching the solution) and three are plausible but incorrect '
|
||||
'alternatives that maintain grammatical consistency. '
|
||||
'You cannot use repeated words!' #TODO: Solve this after
|
||||
f'alternatives that maintain grammatical consistency and {difficulty} CEFR level complexity. '
|
||||
'You cannot use repeated words!'
|
||||
# TODO: Solve this after -> forgot about this TODO just saw now in
|
||||
# 1/11/25 what I meant by this is gpt still sometimes returns repeated
|
||||
# words even with explicit instructions to not do so, this is a general problem
|
||||
# for all exercises, for more robust validation use self._llm.pydantic_prediction
|
||||
# or implement a method that calls a mapper, catches validation error messages
|
||||
# from that mapper and asks gpt to retry if creating a pydantic model for each
|
||||
# operation proves to be unsustainable
|
||||
)
|
||||
}
|
||||
]
|
||||
|
||||
@@ -10,16 +10,16 @@ class MultipleChoice:
|
||||
self._mc_variants = mc_variants
|
||||
|
||||
async def gen_multiple_choice(
|
||||
self, mc_variant: str, quantity: int, start_id: int = 1
|
||||
self, mc_variant: str, quantity: int, difficulty: str, start_id: int = 1
|
||||
):
|
||||
mc_template = self._mc_variants[mc_variant]
|
||||
blank_mod = " blank space " if mc_variant == "blank_space" else " "
|
||||
|
||||
gen_multiple_choice_for_text: str = (
|
||||
'Generate {quantity} multiple choice{blank}questions of 4 options for an english level exam, some easy '
|
||||
'questions, some intermediate questions and some advanced questions. Ensure that the questions cover '
|
||||
'a range of topics such as verb tense, subject-verb agreement, pronoun usage, sentence structure, and '
|
||||
'punctuation. Make sure every question only has 1 correct answer.'
|
||||
'Generate {quantity} multiple choice{blank}questions of 4 options for an english level exam of {difficulty} '
|
||||
'CEFR level, some easy questions, some intermediate questions and some advanced questions. Ensure that '
|
||||
'the questions cover a range of topics such as verb tense, subject-verb agreement, pronoun usage, sentence '
|
||||
'structure, and punctuation. Make sure every question only has 1 correct answer.'
|
||||
)
|
||||
|
||||
messages = [
|
||||
@@ -31,7 +31,7 @@ class MultipleChoice:
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": gen_multiple_choice_for_text.format(quantity=str(quantity), blank=blank_mod)
|
||||
"content": gen_multiple_choice_for_text.format(quantity=str(quantity), blank=blank_mod, difficulty=difficulty)
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -13,11 +13,11 @@ class PassageUtas:
|
||||
self._mc_variants = mc_variants
|
||||
|
||||
async def gen_reading_passage_utas(
|
||||
self, start_id, mc_quantity: int, topic: Optional[str], word_size: Optional[int] # sa_quantity: int,
|
||||
self, start_id, mc_quantity: int, difficulty: str, topic: Optional[str] = None, word_size: Optional[int] = None# sa_quantity: int,
|
||||
):
|
||||
|
||||
passage = await self._reading_service.generate_reading_passage(1, topic, word_size)
|
||||
mc_exercises = await self._gen_text_multiple_choice_utas(passage["text"], start_id, mc_quantity)
|
||||
mc_exercises = await self._gen_text_multiple_choice_utas(passage["text"], start_id, mc_quantity, difficulty)
|
||||
mc_exercises["type"] = "multipleChoice"
|
||||
"""
|
||||
exercises: {
|
||||
@@ -61,7 +61,7 @@ class PassageUtas:
|
||||
|
||||
return question["questions"]
|
||||
|
||||
async def _gen_text_multiple_choice_utas(self, text: str, start_id: int, mc_quantity: int):
|
||||
async def _gen_text_multiple_choice_utas(self, text: str, start_id: int, mc_quantity: int, difficulty: str):
|
||||
json_template = self._mc_variants["text_mc_utas"]
|
||||
|
||||
messages = [
|
||||
@@ -71,7 +71,9 @@ class PassageUtas:
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": f'Generate {mc_quantity} multiple choice questions of 4 options for this text:\n{text}'
|
||||
"content": (
|
||||
f'Generate {mc_quantity} multiple choice questions of 4 options, {difficulty} CEFR '
|
||||
f'level difficulty, for this text:\n{text}')
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import json
|
||||
import random
|
||||
import uuid
|
||||
|
||||
from ielts_be.configs.constants import EducationalContent
|
||||
from ielts_be.services import ILLMService
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user