3 Commits

Author SHA1 Message Date
Tiago Ribeiro
26ad153f7c Merged in develop (pull request #51)
Develop
2025-01-06 21:33:05 +00:00
Tiago Ribeiro
7d04b144c4 Merge branch 'develop' 2024-12-23 16:39:03 +00:00
carlos.mesquita
111108556b Merged in feature/training-content (pull request #30)
Pydantic was causing validation errors when passportID was an int

Approved-by: Tiago Ribeiro
2024-09-08 20:49:13 +00:00
29 changed files with 71 additions and 172 deletions

View File

@@ -1,5 +1,4 @@
import random
from typing import List
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Path, Query, UploadFile
@@ -32,7 +31,7 @@ async def upload(
@inject
async def generate_listening_dialog(
section: int = Path(..., ge=1, le=4),
difficulty: List[str] = Query(default=None),
difficulty: str = Query(default=None),
topic: str = Query(default=None),
listening_controller: IListeningController = Depends(Provide[controller])
):

View File

@@ -59,7 +59,7 @@ async def get_speaking_task(
topic: Optional[str] = Query(None),
first_topic: Optional[str] = Query(None),
second_topic: Optional[str] = Query(None),
difficulty: List[str] = Query(default=None),
difficulty: Optional[str] = None,
speaking_controller: ISpeakingController = Depends(Provide[controller])
):
if not second_topic:
@@ -67,7 +67,8 @@ async def get_speaking_task(
else:
topic_or_first_topic = first_topic if first_topic else random.choice(EducationalContent.MTI_TOPICS)
difficulty = [random.choice(EducationalContent.DIFFICULTIES)] if not difficulty else difficulty
if not difficulty:
difficulty = random.choice(random.choice(EducationalContent.DIFFICULTIES))
second_topic = second_topic if second_topic else random.choice(EducationalContent.MTI_TOPICS)
return await speaking_controller.get_speaking_part(task, topic_or_first_topic, second_topic, difficulty)

View File

@@ -20,10 +20,10 @@ writing_router = APIRouter()
async def generate_writing_academic(
task: int = Path(..., ge=1, le=2),
file: UploadFile = File(...),
difficulty: List[str] = Query(default=None),
difficulty: Optional[List[str]] = None,
writing_controller: IWritingController = Depends(Provide[controller])
):
difficulty = [random.choice(EducationalContent.DIFFICULTIES)] if not difficulty else difficulty
difficulty = random.choice(EducationalContent.DIFFICULTIES) if not difficulty else difficulty
return await writing_controller.get_writing_task_academic_question(task, file, difficulty)
@@ -34,10 +34,10 @@ async def generate_writing_academic(
@inject
async def generate_writing(
task: int = Path(..., ge=1, le=2),
difficulty: List[str] = Query(default=None),
difficulty: Optional[str] = None,
topic: str = Query(default=None),
writing_controller: IWritingController = Depends(Provide[controller])
):
difficulty = [random.choice(EducationalContent.DIFFICULTIES)] if not difficulty else difficulty
difficulty = random.choice(EducationalContent.DIFFICULTIES) if not difficulty else difficulty
topic = random.choice(EducationalContent.MTI_TOPICS) if not topic else topic
return await writing_controller.get_writing_task_general_question(task, topic, difficulty)

View File

@@ -1,5 +1,4 @@
from abc import ABC, abstractmethod
from typing import List
from fastapi import UploadFile
@@ -11,7 +10,7 @@ class IListeningController(ABC):
pass
@abstractmethod
async def generate_listening_dialog(self, section_id: int, topic: str, difficulty: List[str]):
async def generate_listening_dialog(self, section_id: int, topic: str, difficulty: str):
pass
@abstractmethod

View File

@@ -1,11 +1,10 @@
from abc import ABC, abstractmethod
from typing import List
class ISpeakingController(ABC):
@abstractmethod
async def get_speaking_part(self, task: int, topic: str, second_topic: str, difficulty: List[str]):
async def get_speaking_part(self, task: int, topic: str, second_topic: str, difficulty: str):
pass
@abstractmethod

View File

@@ -1,5 +1,4 @@
from abc import ABC, abstractmethod
from typing import List
from fastapi.datastructures import UploadFile
@@ -7,9 +6,9 @@ from fastapi.datastructures import UploadFile
class IWritingController(ABC):
@abstractmethod
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: List[str]):
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: str):
pass
@abstractmethod
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: List[str]):
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: str):
pass

View File

@@ -1,5 +1,4 @@
import io
from typing import List
from fastapi import UploadFile
from fastapi.responses import StreamingResponse, Response
@@ -21,7 +20,7 @@ class ListeningController(IListeningController):
else:
return res
async def generate_listening_dialog(self, section_id: int, topic: str, difficulty: List[str]):
async def generate_listening_dialog(self, section_id: int, topic: str, difficulty: str):
return await self._service.generate_listening_dialog(section_id, topic, difficulty)
async def get_listening_question(self, dto: ListeningExercisesDTO):

View File

@@ -1,5 +1,4 @@
import logging
from typing import List
from ielts_be.controllers import ISpeakingController
from ielts_be.services import ISpeakingService, IVideoGeneratorService
@@ -12,7 +11,7 @@ class SpeakingController(ISpeakingController):
self._vid_gen = vid_gen
self._logger = logging.getLogger(__name__)
async def get_speaking_part(self, task: int, topic: str, second_topic: str, difficulty: List[str]):
async def get_speaking_part(self, task: int, topic: str, second_topic: str, difficulty: str):
return await self._service.get_speaking_part(task, topic, second_topic, difficulty)
async def get_avatars(self):

View File

@@ -1,5 +1,3 @@
from typing import List
from fastapi import UploadFile, HTTPException
from ielts_be.controllers import IWritingController
@@ -11,10 +9,10 @@ class WritingController(IWritingController):
def __init__(self, writing_service: IWritingService):
self._service = writing_service
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: List[str]):
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: str):
return await self._service.get_writing_task_general_question(task, topic, difficulty)
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: List[str]):
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: str):
if attachment.content_type not in ['image/jpeg', 'image/png']:
raise HTTPException(status_code=400, detail="Invalid file type. Only JPEG and PNG allowed.")
return await self._service.get_writing_task_academic_question(task, attachment, difficulty)

View File

@@ -12,8 +12,7 @@ class LevelExercises(BaseModel):
sa_qty: Optional[int] = None
mc_qty: Optional[int] = None
topic: Optional[str] = None
difficulty: Optional[str] = None
class LevelExercisesDTO(BaseModel):
exercises: List[LevelExercises]
difficulty: Optional[List[str]] = None
difficulty: Optional[str] = None

View File

@@ -17,12 +17,11 @@ class SaveListeningDTO(BaseModel):
class ListeningExercises(BaseModel):
type: ListeningExerciseType
quantity: int
difficulty: Optional[str] = None
class ListeningExercisesDTO(BaseModel):
text: str
exercises: List[ListeningExercises]
difficulty: Optional[List[str]] = None
difficulty: Optional[str]
class InstructionsDTO(BaseModel):
text: str

View File

@@ -10,9 +10,8 @@ class ReadingExercise(BaseModel):
quantity: int
num_random_words: Optional[int] = Field(1)
max_words: Optional[int] = Field(3)
difficulty: Optional[str] = None
class ReadingDTO(BaseModel):
text: str = Field(...)
exercises: List[ReadingExercise] = Field(...)
difficulty: Optional[List[str]] = None
difficulty: Optional[str] = None

View File

@@ -2,12 +2,10 @@ from .file import FileHelper
from .text import TextHelper
from .token_counter import count_tokens
from .exercises import ExercisesHelper
from .difficulty import DifficultyHelper
__all__ = [
"FileHelper",
"TextHelper",
"count_tokens",
"ExercisesHelper",
"DifficultyHelper"
]

View File

@@ -1,40 +0,0 @@
import math
import random
from typing import Optional, List, Iterator
from ielts_be.configs.constants import EducationalContent
class DifficultyHelper:
def __init__(self, difficulties: Optional[List[str]]):
self.difficulties = difficulties
self.distributed: Optional[Iterator[str]] = None
def distribute_for_count(self, count: int) -> None:
if not self.difficulties or count == 0:
return
result = []
remaining = count
difficulties_count = len(self.difficulties)
for i, diff in enumerate(self.difficulties):
if i == difficulties_count - 1:
slots = remaining
else:
slots = math.ceil(remaining / (difficulties_count - i))
result.extend([diff] * slots)
remaining -= slots
self.distributed = iter(result)
def pick_difficulty(self, difficulty: Optional[str]) -> str:
if difficulty:
return difficulty if difficulty != "Random" else random.choice(EducationalContent.DIFFICULTIES)
if self.distributed:
return next(self.distributed)
return random.choice(EducationalContent.DIFFICULTIES)

View File

@@ -9,7 +9,7 @@ from fastapi import UploadFile
class IListeningService(ABC):
@abstractmethod
async def generate_listening_dialog( self, section_id: int, topic: str, difficulty: List[str]):
async def generate_listening_dialog( self, section_id: int, topic: str, difficulty: str):
pass
@abstractmethod

View File

@@ -6,7 +6,7 @@ class ISpeakingService(ABC):
@abstractmethod
async def get_speaking_part(
self, part: int, topic: str, second_topic: str, difficulty: List[str]
self, part: int, topic: str, second_topic: str, difficulty: str
) -> Dict:
pass

View File

@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Optional, List
from typing import Optional
from fastapi import UploadFile
@@ -7,11 +7,11 @@ from fastapi import UploadFile
class IWritingService(ABC):
@abstractmethod
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: List[str]):
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: str):
pass
@abstractmethod
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: List[str]):
async def get_writing_task_academic_question(self, task: int, attachment: UploadFile, difficulty: str):
pass
@abstractmethod

View File

@@ -8,7 +8,6 @@ import random
from ielts_be.configs.constants import EducationalContent
from ielts_be.dtos.level import LevelExercisesDTO
from ielts_be.helpers import DifficultyHelper
from ielts_be.repositories import IDocumentStore
from ielts_be.services import (
ILevelService, ILLMService, IReadingService,
@@ -51,21 +50,19 @@ 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, difficulty):
async def _generate_exercise(self, req_exercise, start_id):
if req_exercise.type == "mcBlank":
questions = await self._mc.gen_multiple_choice("blank_space", req_exercise.quantity, difficulty, start_id)
questions = await self._mc.gen_multiple_choice("blank_space", req_exercise.quantity, 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, difficulty, start_id)
questions = await self._mc.gen_multiple_choice("underline", req_exercise.quantity, 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":
@@ -73,42 +70,34 @@ 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):
start_ids = []
current_id = 1
tasks = []
distributor = DifficultyHelper(dto.difficulty)
none_count = sum(1 for ex in dto.exercises if ex.difficulty is None)
distributor.distribute_for_count(none_count)
for req_exercise in dto.exercises:
difficulty = distributor.pick_difficulty(req_exercise.difficulty)
tasks.append(
self._generate_exercise(req_exercise, current_id, difficulty)
)
start_ids.append(current_id)
current_id += req_exercise.quantity
tasks = [
self._generate_exercise(req_exercise, start_id)
for req_exercise, start_id in zip(dto.exercises, start_ids)
]
questions = await gather(*tasks)
questions = [{'id': str(uuid4()), **exercise} for exercise in questions]
@@ -116,12 +105,10 @@ 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):
difficulty = random.choice(EducationalContent.DIFFICULTIES)
return await self._mc.gen_multiple_choice(mc_variant, quantity, difficulty, start_id)
return await self._mc.gen_multiple_choice(mc_variant, quantity, start_id)
async def gen_reading_passage_utas(self, start_id, mc_quantity: int, topic=Optional[str]): # sa_quantity: int,
difficulty = random.choice(EducationalContent.DIFFICULTIES)
return await self._passage_utas.gen_reading_passage_utas(start_id, mc_quantity, difficulty, topic)
return await self._passage_utas.gen_reading_passage_utas(start_id, mc_quantity, 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)

View File

@@ -11,10 +11,12 @@ class FillBlanks:
async def gen_fill_blanks(
self, start_id: int, quantity: int, difficulty: str, size: int = 300, topic=None
self, start_id: int, quantity: int, size: int = 300, topic=None
):
if not topic:
topic = random.choice(EducationalContent.MTI_TOPICS)
print(quantity)
print(start_id)
messages = [
{
"role": "system",
@@ -32,15 +34,8 @@ 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 '
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
'alternatives that maintain grammatical consistency. '
'You cannot use repeated words!' #TODO: Solve this after
)
}
]

View File

@@ -10,16 +10,16 @@ class MultipleChoice:
self._mc_variants = mc_variants
async def gen_multiple_choice(
self, mc_variant: str, quantity: int, difficulty: str, start_id: int = 1
self, mc_variant: str, quantity: int, 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 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.'
'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.'
)
messages = [
@@ -31,7 +31,7 @@ class MultipleChoice:
},
{
"role": "user",
"content": gen_multiple_choice_for_text.format(quantity=str(quantity), blank=blank_mod, difficulty=difficulty)
"content": gen_multiple_choice_for_text.format(quantity=str(quantity), blank=blank_mod)
}
]

View File

@@ -13,11 +13,11 @@ class PassageUtas:
self._mc_variants = mc_variants
async def gen_reading_passage_utas(
self, start_id, mc_quantity: int, difficulty: str, topic: Optional[str] = None, word_size: Optional[int] = None# sa_quantity: int,
self, start_id, mc_quantity: int, topic: Optional[str], word_size: Optional[int] # 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, difficulty)
mc_exercises = await self._gen_text_multiple_choice_utas(passage["text"], start_id, mc_quantity)
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, difficulty: str):
async def _gen_text_multiple_choice_utas(self, text: str, start_id: int, mc_quantity: int):
json_template = self._mc_variants["text_mc_utas"]
messages = [
@@ -71,9 +71,7 @@ class PassageUtas:
},
{
"role": "user",
"content": (
f'Generate {mc_quantity} multiple choice questions of 4 options, {difficulty} CEFR '
f'level difficulty, for this text:\n{text}')
"content": f'Generate {mc_quantity} multiple choice questions of 4 options for this text:\n{text}'
},
{
"role": "user",

View File

@@ -1,8 +1,6 @@
import json
import random
import uuid
from ielts_be.configs.constants import EducationalContent
from ielts_be.services import ILLMService

View File

@@ -1,7 +1,7 @@
import asyncio
from logging import getLogger
import random
from typing import Dict, Any, Union, List
from typing import Dict, Any, Union
from starlette.datastructures import UploadFile
@@ -13,7 +13,7 @@ from ielts_be.configs.constants import (
NeuralVoices, GPTModels, TemperatureSettings, EducationalContent,
FieldsAndExercises
)
from ielts_be.helpers import FileHelper, DifficultyHelper
from ielts_be.helpers import FileHelper
from .audio_to_dialog import AudioToDialog
from .import_listening import ImportListeningModule
from .write_blank_forms import WriteBlankForms
@@ -21,6 +21,7 @@ from .write_blanks import WriteBlanks
from .write_blank_notes import WriteBlankNotes
from ..shared import TrueFalse, MultipleChoice
class ListeningService(IListeningService):
CONVERSATION_TAIL = (
@@ -93,8 +94,7 @@ class ListeningService(IListeningService):
return await self._import.import_from_file(exercises, solutions)
async def generate_listening_dialog(self, section: int, topic: str, difficulty: List[str]):
# TODO: difficulties to difficulty
async def generate_listening_dialog(self, section: int, topic: str, difficulty: str):
return await self._sections[f'section_{section}']["generate_dialogue"](section, topic)
async def transcribe_dialog(self, audio: UploadFile):
@@ -135,11 +135,6 @@ class ListeningService(IListeningService):
start_id = 1
exercise_tasks = []
diff_helper = DifficultyHelper(dto.difficulty)
none_count = sum(1 for ex in dto.exercises if ex.difficulty is None)
diff_helper.distribute_for_count(none_count)
for req_exercise in dto.exercises:
exercise_tasks.append(
self._generate_exercise(
@@ -147,7 +142,7 @@ class ListeningService(IListeningService):
"dialog or monologue",
dto.text,
start_id,
diff_helper.pick_difficulty(req_exercise.difficulty)
dto.difficulty
)
)
start_id += req_exercise.quantity
@@ -162,7 +157,6 @@ class ListeningService(IListeningService):
question = await self._multiple_choice.gen_multiple_choice(
text, req_exercise.quantity, start_id, difficulty, n_options
)
question["difficulty"] = difficulty
self._logger.info(f"Added multiple choice: {question}")
return question
@@ -171,7 +165,6 @@ class ListeningService(IListeningService):
dialog_type, text, req_exercise.quantity, start_id, difficulty
)
question["variant"] = "questions"
question["difficulty"] = difficulty
self._logger.info(f"Added write blanks questions: {question}")
return question
@@ -180,7 +173,6 @@ class ListeningService(IListeningService):
dialog_type, text, req_exercise.quantity, start_id, difficulty
)
question["variant"] = "fill"
question["difficulty"] = difficulty
self._logger.info(f"Added write blanks notes: {question}")
return question
@@ -189,14 +181,12 @@ class ListeningService(IListeningService):
dialog_type, text, req_exercise.quantity, start_id, difficulty
)
question["variant"] = "form"
question["difficulty"] = difficulty
self._logger.info(f"Added write blanks form: {question}")
return question
elif req_exercise.type == "trueFalse":
question = await self._true_false.gen_true_false_not_given_exercise(
text, req_exercise.quantity, start_id, difficulty, "listening"
)
question["difficulty"] = difficulty
self._logger.info(f"Added trueFalse: {question}")
return question

View File

@@ -5,7 +5,7 @@ from fastapi import UploadFile
from ielts_be.configs.constants import GPTModels, FieldsAndExercises, TemperatureSettings
from ielts_be.dtos.reading import ReadingDTO
from ielts_be.helpers import ExercisesHelper, DifficultyHelper
from ielts_be.helpers import ExercisesHelper
from ielts_be.services import IReadingService, ILLMService
from .fill_blanks import FillBlanks
from .idea_match import IdeaMatch
@@ -84,7 +84,6 @@ class ReadingService(IReadingService):
question = await self._fill_blanks.gen_summary_fill_blanks_exercise(
text, req_exercise.quantity, start_id, difficulty, req_exercise.num_random_words
)
question["difficulty"] = difficulty
self._logger.info(f"Added fill blanks: {question}")
return question
@@ -92,7 +91,6 @@ class ReadingService(IReadingService):
question = await self._true_false.gen_true_false_not_given_exercise(
text, req_exercise.quantity, start_id, difficulty, "reading"
)
question["difficulty"] = difficulty
self._logger.info(f"Added trueFalse: {question}")
return question
@@ -102,7 +100,6 @@ class ReadingService(IReadingService):
)
if ExercisesHelper.answer_word_limit_ok(question):
question["difficulty"] = difficulty
self._logger.info(f"Added write blanks: {question}")
return question
else:
@@ -113,7 +110,6 @@ class ReadingService(IReadingService):
question = await self._paragraph_match.gen_paragraph_match_exercise(
text, req_exercise.quantity, start_id
)
question["difficulty"] = difficulty
self._logger.info(f"Added paragraph match: {question}")
return question
@@ -122,14 +118,12 @@ class ReadingService(IReadingService):
text, req_exercise.quantity, start_id
)
question["variant"] = "ideaMatch"
question["difficulty"] = difficulty
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
)
question["difficulty"] = difficulty
self._logger.info(f"Added multiple choice: {question}")
return question
@@ -137,18 +131,13 @@ class ReadingService(IReadingService):
exercise_tasks = []
start_id = 1
diff_helper = DifficultyHelper(dto.difficulty)
none_count = sum(1 for ex in dto.exercises if ex.difficulty is None)
diff_helper.distribute_for_count(none_count)
for req_exercise in dto.exercises:
exercise_tasks.append(
self._generate_single_exercise(
req_exercise,
dto.text,
start_id,
diff_helper.pick_difficulty(req_exercise.difficulty)
dto.difficulty
)
)
start_id += req_exercise.quantity

View File

@@ -1,6 +1,5 @@
import logging
import re
import random
from typing import Dict, List
@@ -100,9 +99,8 @@ class SpeakingService(ISpeakingService):
}
async def get_speaking_part(
self, part: int, topic: str, second_topic: str, difficulty: List[str]
self, part: int, topic: str, second_topic: str, difficulty: str
) -> Dict:
diff = difficulty[0] if len(difficulty) == 1 else random.choice(difficulty)
task_values = self._tasks[f'task_{part}']['get']
if part == 1:
@@ -159,7 +157,7 @@ class SpeakingService(ISpeakingService):
]
response["type"] = part
response["difficulty"] = diff
response["difficulty"] = difficulty
if part in {2, 3}:
response["topic"] = topic

View File

@@ -1,4 +1,3 @@
import random
from typing import List, Dict, Optional
from fastapi import UploadFile
@@ -17,8 +16,7 @@ class WritingService(IWritingService):
self._llm = llm
self._grade = GradeWriting(llm, file_storage, ai_detector)
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: List[str]):
diff = difficulty[0] if len(difficulty) == 1 else random.choice(difficulty)
async def get_writing_task_general_question(self, task: int, topic: str, difficulty: str):
messages = [
{
"role": "system",
@@ -26,7 +24,7 @@ class WritingService(IWritingService):
'You are a helpful assistant designed to output JSON on this format: {"prompt": "prompt content"}'
)
},
*get_writing_args_general(task, topic, diff)
*get_writing_args_general(task, topic, difficulty)
]
llm_model = GPTModels.GPT_3_5_TURBO if task == 1 else GPTModels.GPT_4_O
@@ -42,12 +40,11 @@ class WritingService(IWritingService):
return {
"question": self._add_newline_before_hyphen(question) if task == 1 else question,
"topic": topic,
"difficulty": diff
"difficulty": difficulty,
"topic": topic
}
async def get_writing_task_academic_question(self, task: int, file: UploadFile, difficulty: List[str]):
diff = difficulty[0] if len(difficulty) == 1 else random.choice(difficulty)
async def get_writing_task_academic_question(self, task: int, file: UploadFile, difficulty: str):
messages = [
{
"role": "system",
@@ -55,7 +52,7 @@ class WritingService(IWritingService):
'You are a helpful assistant designed to output JSON on this format: {"prompt": "prompt content"}'
)
},
*(await get_writing_args_academic(task, file, diff))
*(await get_writing_args_academic(task, file))
]
response = await self._llm.prediction(
@@ -69,7 +66,7 @@ class WritingService(IWritingService):
return {
"question": self._add_newline_before_hyphen(question) if task == 1 else question,
"difficulty": diff,
"difficulty": difficulty,
}
async def grade_writing_task(self, task: int, question: str, answer: str, attachment: Optional[str] = None):

View File

@@ -4,7 +4,7 @@ from typing import List, Dict
from fastapi.datastructures import UploadFile
async def get_writing_args_academic(task: int, attachment: UploadFile, difficulty: str) -> List[Dict]:
async def get_writing_args_academic(task: int, attachment: UploadFile) -> List[Dict]:
writing_args = {
"1": {
"prompt": (
@@ -16,8 +16,7 @@ async def get_writing_args_academic(task: int, attachment: UploadFile, difficult
'The generated prompt must:\n'
'1. Clearly describe the type of visual representation in the image\n'
'2. Provide a concise context for the data shown\n'
f'3. Be adequate for {difficulty} CEFR level users\n'
'4. End with the standard IELTS Task 1 Academic instruction:\n'
'3. End with the standard IELTS Task 1 Academic instruction:\n'
'"Summarise the information by selecting and reporting the main features, and make comparisons where relevant."'
)
},

View File

@@ -16,8 +16,8 @@ class TrainingContentKnowledgeBase(IKnowledgeBase):
self._tips = None # self._read_json(path)
self._category_metadata = None
self._indices = None
self._logger = getLogger(__name__)
self.load_indices_and_metadata()
self._logger = getLogger(__name__)
@staticmethod
def _read_json(path: str) -> Dict[str, any]:

View File

@@ -3,5 +3,5 @@ from .logger import suppress_loggers
__all__ = [
"handle_exception",
"suppress_loggers",
"suppress_loggers"
]