Brushed up the backend, added writing task 1 academic prompt gen and grading ENCOA-274
This commit is contained in:
5
ielts_be/mappers/__init__.py
Normal file
5
ielts_be/mappers/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from .level import LevelMapper
|
||||
|
||||
__all__ = [
|
||||
"LevelMapper"
|
||||
]
|
||||
71
ielts_be/mappers/level.py
Normal file
71
ielts_be/mappers/level.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from typing import Dict, Any
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
from ielts_be.dtos.exams.level import (
|
||||
MultipleChoiceExercise,
|
||||
FillBlanksExercise,
|
||||
Part, Exam, Text
|
||||
)
|
||||
from ielts_be.dtos.sheet import Sheet, Option, MultipleChoiceQuestion, FillBlanksWord
|
||||
|
||||
|
||||
class LevelMapper:
|
||||
|
||||
@staticmethod
|
||||
def map_to_exam_model(response: Dict[str, Any]) -> Exam:
|
||||
parts = []
|
||||
for part in response['parts']:
|
||||
part_exercises = part['exercises']
|
||||
text = part.get('text', None)
|
||||
|
||||
exercises = []
|
||||
for exercise in part_exercises:
|
||||
exercise_type = exercise['type']
|
||||
if exercise_type == 'multipleChoice':
|
||||
exercise_model = MultipleChoiceExercise(**exercise)
|
||||
elif exercise_type == 'fillBlanks':
|
||||
exercise_model = FillBlanksExercise(**exercise)
|
||||
else:
|
||||
raise ValidationError(f"Unknown exercise type: {exercise_type}")
|
||||
|
||||
exercises.append(exercise_model)
|
||||
|
||||
part_kwargs = {"exercises": exercises}
|
||||
if text is not None and text.get('content', None):
|
||||
title = text.get('title', 'Untitled')
|
||||
if title == '':
|
||||
title = 'Untitled'
|
||||
part_kwargs["text"] = Text(title=title, content=text['content'])
|
||||
else:
|
||||
part_kwargs["text"] = None
|
||||
|
||||
part_model = Part(**part_kwargs)
|
||||
parts.append(part_model)
|
||||
|
||||
return Exam(parts=parts)
|
||||
|
||||
@staticmethod
|
||||
def map_to_sheet(response: Dict[str, Any]) -> Sheet:
|
||||
components = []
|
||||
|
||||
for item in response["components"]:
|
||||
component_type = item["type"]
|
||||
|
||||
if component_type == "multipleChoice":
|
||||
options = [Option(id=opt["id"], text=opt["text"]) for opt in item["options"]]
|
||||
components.append(MultipleChoiceQuestion(
|
||||
id=item["id"],
|
||||
prompt=item["prompt"],
|
||||
variant=item.get("variant", "text"),
|
||||
options=options
|
||||
))
|
||||
elif component_type == "fillBlanks":
|
||||
components.append(FillBlanksWord(
|
||||
id=item["id"],
|
||||
options=item["options"]
|
||||
))
|
||||
else:
|
||||
components.append(item)
|
||||
|
||||
return Sheet(components=components)
|
||||
112
ielts_be/mappers/listening.py
Normal file
112
ielts_be/mappers/listening.py
Normal file
@@ -0,0 +1,112 @@
|
||||
from typing import Dict, Any, List, Union, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ielts_be.dtos.exams.listening import (
|
||||
TrueFalseExercise,
|
||||
MultipleChoiceExercise,
|
||||
WriteBlanksExercise,
|
||||
ListeningExam,
|
||||
ListeningSection,
|
||||
WriteBlanksVariant, WriteBlankSolution, WriteBlanksQuestionExercise, WriteBlankQuestion
|
||||
)
|
||||
|
||||
class ListeningQuestionSection(BaseModel):
|
||||
exercises: List[Union[TrueFalseExercise, MultipleChoiceExercise, WriteBlanksQuestionExercise]]
|
||||
|
||||
class ListeningQuestionExam(BaseModel):
|
||||
parts: List[ListeningQuestionSection]
|
||||
minTimer: Optional[int]
|
||||
module: str = "listening"
|
||||
|
||||
class WriteBlankProcessor:
|
||||
@staticmethod
|
||||
def to_question_model(exercise_data: Dict[str, Any]) -> WriteBlanksQuestionExercise:
|
||||
questions = [
|
||||
WriteBlankQuestion(
|
||||
id=q["id"],
|
||||
prompt=q["prompt"],
|
||||
solution=q["solution"]
|
||||
)
|
||||
for q in exercise_data.get("questions", [])
|
||||
]
|
||||
|
||||
return WriteBlanksQuestionExercise(
|
||||
type="writeBlanks",
|
||||
prompt=exercise_data.get("prompt"),
|
||||
maxWords=exercise_data.get("maxWords"),
|
||||
questions=questions,
|
||||
variant=exercise_data.get("variant", "questions")
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def to_text_model(question_model: WriteBlanksQuestionExercise) -> WriteBlanksExercise:
|
||||
if question_model.variant == WriteBlanksVariant.QUESTIONS:
|
||||
text = '\\n'.join(f"{q.prompt} {{{{{q.id}}}}}" for q in question_model.questions)
|
||||
elif question_model.variant == WriteBlanksVariant.FILL:
|
||||
text = ' '.join(f"{q.prompt}" for q in question_model.questions)
|
||||
elif question_model.variant == WriteBlanksVariant.FORM:
|
||||
text = '\\n'.join(f"{q.prompt}" for q in question_model.questions)
|
||||
else:
|
||||
raise ValueError(f"Unknown variant: {question_model.variant}")
|
||||
|
||||
solutions = [
|
||||
WriteBlankSolution(id=q.id, solution=q.solution)
|
||||
for q in question_model.questions
|
||||
]
|
||||
|
||||
return WriteBlanksExercise(
|
||||
type="writeBlanks",
|
||||
prompt=question_model.prompt,
|
||||
maxWords=question_model.maxWords,
|
||||
text=text,
|
||||
solutions=solutions,
|
||||
variant=question_model.variant
|
||||
)
|
||||
|
||||
|
||||
class ListeningMapper:
|
||||
@staticmethod
|
||||
def map_to_test_model(response: Dict[str, Any]) -> ListeningExam:
|
||||
question_parts = []
|
||||
for section in response.get('parts', []):
|
||||
section_exercises = []
|
||||
|
||||
for exercise in section['exercises']:
|
||||
exercise_type = exercise['type']
|
||||
|
||||
if exercise_type == 'trueFalse':
|
||||
section_exercises.append(TrueFalseExercise(**exercise))
|
||||
elif exercise_type == 'multipleChoice':
|
||||
section_exercises.append(MultipleChoiceExercise(**exercise))
|
||||
elif exercise_type == 'writeBlanks':
|
||||
question_model = WriteBlankProcessor.to_question_model(exercise)
|
||||
section_exercises.append(question_model)
|
||||
else:
|
||||
raise ValueError(f"Unknown exercise type: {exercise_type}")
|
||||
|
||||
question_parts.append(ListeningQuestionSection(exercises=section_exercises))
|
||||
|
||||
question_exam = ListeningQuestionExam(
|
||||
parts=question_parts,
|
||||
minTimer=response.get('minTimer'),
|
||||
module="listening"
|
||||
)
|
||||
|
||||
final_parts = []
|
||||
for section in question_exam.parts:
|
||||
final_exercises = []
|
||||
|
||||
for exercise in section.exercises:
|
||||
if isinstance(exercise, WriteBlanksQuestionExercise):
|
||||
final_exercises.append(WriteBlankProcessor.to_text_model(exercise))
|
||||
else:
|
||||
final_exercises.append(exercise)
|
||||
|
||||
final_parts.append(ListeningSection(exercises=final_exercises))
|
||||
|
||||
return ListeningExam(
|
||||
parts=final_parts,
|
||||
minTimer=response.get('minTimer'),
|
||||
module="listening"
|
||||
)
|
||||
44
ielts_be/mappers/reading.py
Normal file
44
ielts_be/mappers/reading.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from typing import Dict, Any
|
||||
|
||||
from ielts_be.dtos.exams.reading import (
|
||||
Part, Exam, Context, FillBlanksExercise,
|
||||
TrueFalseExercise, MatchSentencesExercise,
|
||||
WriteBlanksExercise, MultipleChoice
|
||||
)
|
||||
|
||||
|
||||
class ReadingMapper:
|
||||
|
||||
@staticmethod
|
||||
def map_to_exam_model(response: Dict[str, Any]) -> Exam:
|
||||
parts = []
|
||||
for part in response['parts']:
|
||||
part_exercises = part['exercises']
|
||||
context = Context(**part['text'])
|
||||
|
||||
model_map = {
|
||||
'fillBlanks': FillBlanksExercise,
|
||||
'trueFalse': TrueFalseExercise,
|
||||
'matchSentences': MatchSentencesExercise,
|
||||
'writeBlanks': WriteBlanksExercise,
|
||||
'multipleChoice': MultipleChoice,
|
||||
}
|
||||
|
||||
exercises = []
|
||||
for exercise in part_exercises:
|
||||
exercise_type = exercise['type']
|
||||
if exercise_type in model_map:
|
||||
model_class = model_map[exercise_type]
|
||||
exercises.append(model_class(**exercise))
|
||||
else:
|
||||
raise ValueError(f"Unknown exercise type: {exercise_type}")
|
||||
|
||||
part_kwargs = {
|
||||
"exercises": exercises,
|
||||
"text": context
|
||||
}
|
||||
|
||||
part_model = Part(**part_kwargs)
|
||||
parts.append(part_model)
|
||||
|
||||
return Exam(parts=parts, minTimer=response["minTimer"])
|
||||
Reference in New Issue
Block a user