ENCOA-256: Some more changes to level prompt and added mc to reading
This commit is contained in:
@@ -47,6 +47,7 @@ class ReadingExerciseType(str, Enum):
|
||||
trueFalse = "trueFalse"
|
||||
paragraphMatch = "paragraphMatch"
|
||||
ideaMatch = "ideaMatch"
|
||||
multipleChoice = "multipleChoice"
|
||||
|
||||
|
||||
class ListeningExerciseType(str, Enum):
|
||||
|
||||
@@ -35,7 +35,7 @@ class UploadLevelModule:
|
||||
#completion: Coroutine[Any, Any, Exam] = (
|
||||
# self._png_completion(path_id) if file_has_images else self._html_completion(path_id)
|
||||
#)
|
||||
response = await self._html_completion(path_id)
|
||||
response = await self._html_completion(path_id, solutions is not None)
|
||||
|
||||
FileHelper.remove_directory(f'./tmp/{path_id}')
|
||||
|
||||
@@ -69,16 +69,26 @@ class UploadLevelModule:
|
||||
]
|
||||
}
|
||||
|
||||
async def _html_completion(self, path_id: str) -> Exam:
|
||||
async def _html_completion(self, path_id: str, solutions_provided: bool) -> Exam:
|
||||
async with aiofiles.open(f'./tmp/{path_id}/exercises.html', 'r', encoding='utf-8') as f:
|
||||
html = await f.read()
|
||||
|
||||
solutions = []
|
||||
if solutions_provided:
|
||||
async with aiofiles.open(f'./tmp/{path_id}/solutions.html', 'r', encoding='utf-8') as f:
|
||||
solutions_html = await f.read()
|
||||
solutions.append({
|
||||
"role": "user",
|
||||
"content": f'The solutions to the question sheet are the following:\n\n{solutions_html}'
|
||||
})
|
||||
|
||||
return await self._llm.pydantic_prediction(
|
||||
[self._gpt_instructions_html(),
|
||||
{
|
||||
"role": "user",
|
||||
"content": html
|
||||
}
|
||||
},
|
||||
*solutions
|
||||
],
|
||||
LevelMapper.map_to_exam_model,
|
||||
str(self._level_json_schema())
|
||||
@@ -122,8 +132,10 @@ class UploadLevelModule:
|
||||
|
||||
'IMPORTANT: As stated earlier your job is to structure the questions into PARTS not SECTION, this means '
|
||||
'that if there is for example: Section 1, Part 1 and Part 2, Section 2, Part 1 and Part 2, you MUST '
|
||||
'place in the parts array 4 parts NOT 2 parts with the exercises of both parts! You must strictly '
|
||||
'adhere to this instruction, do not mistake sections for parts!\n'
|
||||
'place in the parts array 4 parts NOT 2 parts with the exercises of both parts! If there are no sections '
|
||||
'and only Parts then group them by parts, and when I say parts I mean it in the fucking literal sense of the'
|
||||
' word Part x which is in the html. '
|
||||
'You must strictly adhere to this instruction, do not mistake sections for parts!\n'
|
||||
|
||||
'The templates for the exercises are the following:\n'
|
||||
'- blank space multiple choice, underline multiple choice and reading passage multiple choice: '
|
||||
@@ -164,17 +176,17 @@ class UploadLevelModule:
|
||||
"prompt": "Click a blank to select the appropriate word for it.",
|
||||
"text": (
|
||||
"<The whole text for the exercise with replacements for blank spaces and their "
|
||||
"ids with {{<question id>}} with 2 newlines between paragraphs>"
|
||||
"ids with {{<question id/number>}} with 2 newlines between paragraphs>"
|
||||
),
|
||||
"solutions": [
|
||||
{
|
||||
"id": "<question id>",
|
||||
"id": "<question number>",
|
||||
"solution": "<the option that holds the solution>"
|
||||
}
|
||||
],
|
||||
"words": [
|
||||
{
|
||||
"id": "<question id>",
|
||||
"id": "<question number>",
|
||||
"options": {
|
||||
"A": "<a option>",
|
||||
"B": "<b option>",
|
||||
@@ -198,7 +210,7 @@ class UploadLevelModule:
|
||||
self._multiple_choice_png(),
|
||||
{"type": "blanksPassage", "text": (
|
||||
"<The whole text for the exercise with replacements for blank spaces and their "
|
||||
"ids with {{<question id>}} with 2 newlines between paragraphs>"
|
||||
"ids with {{<question number>}} with 2 newlines between paragraphs>"
|
||||
)},
|
||||
{"type": "passage", "context": (
|
||||
"<reading passages without paragraphs or line numbers, with 2 newlines between paragraphs>"
|
||||
|
||||
@@ -14,11 +14,10 @@ from app.configs.constants import (
|
||||
)
|
||||
from app.helpers import FileHelper
|
||||
from .import_listening import ImportListeningModule
|
||||
from .multiple_choice import MultipleChoice
|
||||
from .write_blank_forms import WriteBlankForms
|
||||
from .write_blanks import WriteBlanks
|
||||
from .write_blank_notes import WriteBlankNotes
|
||||
from ..shared import TrueFalse
|
||||
from ..shared import TrueFalse, MultipleChoice
|
||||
|
||||
|
||||
class ListeningService(IListeningService):
|
||||
@@ -128,7 +127,7 @@ class ListeningService(IListeningService):
|
||||
if req_exercise.type == "multipleChoice" or req_exercise.type == "multipleChoice3Options":
|
||||
n_options = 4 if req_exercise.type == "multipleChoice" else 3
|
||||
question = await self._multiple_choice.gen_multiple_choice(
|
||||
dialog_type, text, req_exercise.quantity, start_id, difficulty, n_options
|
||||
text, req_exercise.quantity, start_id, difficulty, n_options
|
||||
)
|
||||
self._logger.info(f"Added multiple choice: {question}")
|
||||
return question
|
||||
|
||||
@@ -10,7 +10,7 @@ from app.services.abc import IReadingService, ILLMService
|
||||
from .fill_blanks import FillBlanks
|
||||
from .idea_match import IdeaMatch
|
||||
from .paragraph_match import ParagraphMatch
|
||||
from ..shared import TrueFalse
|
||||
from ..shared import TrueFalse, MultipleChoice
|
||||
from .import_reading import ImportReadingModule
|
||||
from .write_blanks import WriteBlanks
|
||||
|
||||
@@ -24,6 +24,7 @@ class ReadingService(IReadingService):
|
||||
self._paragraph_match = ParagraphMatch(llm)
|
||||
self._true_false = TrueFalse(llm)
|
||||
self._write_blanks = WriteBlanks(llm)
|
||||
self._multiple_choice = MultipleChoice(llm)
|
||||
self._logger = getLogger(__name__)
|
||||
self._import = ImportReadingModule(llm)
|
||||
|
||||
@@ -119,6 +120,12 @@ class ReadingService(IReadingService):
|
||||
question["variant"] = "ideaMatch"
|
||||
self._logger.info(f"Added idea match: {question}")
|
||||
return question
|
||||
elif req_exercise.type == "multipleChoice":
|
||||
question = await self._multiple_choice.gen_multiple_choice(
|
||||
text, req_exercise.quantity, start_id, difficulty, 4
|
||||
)
|
||||
self._logger.info(f"Added multiple choice: {question}")
|
||||
return question
|
||||
|
||||
async def generate_reading_exercises(self, dto: ReadingDTO):
|
||||
exercise_tasks = []
|
||||
|
||||
@@ -98,7 +98,11 @@ class ImportReadingModule:
|
||||
]
|
||||
}
|
||||
],
|
||||
"text": "<numbered questions with format in square brackets: [<question text>{{<question number>}}\\\\n] notice how there is a double backslash before the n -> I want an escaped newline in your output> ",
|
||||
"text": (
|
||||
"<numbered questions with format in square brackets: [<question text>{{<question number>}}\\\\n] "
|
||||
"- notice how there the question number inside {{}} -> the text MUST always contain the question number in that format "
|
||||
"- and notice how there is a double backslash before the n -> I want an escaped newline in your output> "
|
||||
),
|
||||
"type": "writeBlanks",
|
||||
"prompt": "<specific instructions for this exercise section>"
|
||||
}
|
||||
@@ -192,13 +196,14 @@ class ImportReadingModule:
|
||||
+ (
|
||||
"Solutions were not provided - analyze the passage carefully to determine correct answers."
|
||||
if not solutions else
|
||||
"Use the provided solutions to fill in all answer fields accurately."
|
||||
"Use the provided solutions to fill in all answer fields accurately, if word answers have all letters "
|
||||
"uppercase convert them to lowercase before assigning them."
|
||||
)
|
||||
+
|
||||
"Pay extra attention to fillblanks exercises the solution and option wording must match in case!"
|
||||
"There can't be options in lowercase and solutions in uppercase!"
|
||||
"Pay extra attention to fillblanks exercises the solution and option wording must match in case! "
|
||||
"There can't be options in lowercase and solutions in uppercase! "
|
||||
"Also PAY ATTENTION TO SECTIONS, these most likely indicate parts, and in each section/part there "
|
||||
"should be a text, if there isn't a title for it choose a reasonable one based on its contents."
|
||||
"should be a text, if there isn't a title for it choose a reasonable one based on its contents. "
|
||||
)
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from .true_false import TrueFalse
|
||||
from .multiple_choice import MultipleChoice
|
||||
|
||||
__all__ = [
|
||||
"TrueFalse"
|
||||
]
|
||||
"TrueFalse",
|
||||
"MultipleChoice"
|
||||
]
|
||||
|
||||
@@ -11,7 +11,7 @@ class MultipleChoice:
|
||||
self._llm = llm
|
||||
|
||||
async def gen_multiple_choice(
|
||||
self, dialog_type: str, text: str, quantity: int, start_id: int, difficulty: str, n_options: int = 4
|
||||
self, text: str, quantity: int, start_id: int, difficulty: str, n_options: int = 4
|
||||
):
|
||||
messages = [
|
||||
{
|
||||
@@ -27,7 +27,7 @@ class MultipleChoice:
|
||||
"role": "user",
|
||||
"content": (
|
||||
f'Generate {quantity} {difficulty} difficulty multiple choice questions of {n_options} '
|
||||
f'options for this {dialog_type}:\n"' + text + '"')
|
||||
f'options for this text:\n"' + text + '"')
|
||||
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user