Brushed up the backend, added writing task 1 academic prompt gen and grading ENCOA-274
This commit is contained in:
13
ielts_be/services/abc/__init__.py
Normal file
13
ielts_be/services/abc/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from .third_parties import *
|
||||
from .exam import *
|
||||
from .training import *
|
||||
from .user import IUserService
|
||||
from .evaluation import IEvaluationService
|
||||
|
||||
__all__ = [
|
||||
"IUserService",
|
||||
"IEvaluationService"
|
||||
]
|
||||
__all__.extend(third_parties.__all__)
|
||||
__all__.extend(exam.__all__)
|
||||
__all__.extend(training.__all__)
|
||||
28
ielts_be/services/abc/evaluation.py
Normal file
28
ielts_be/services/abc/evaluation.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from abc import abstractmethod, ABC
|
||||
|
||||
from fastapi import BackgroundTasks
|
||||
|
||||
from ielts_be.dtos.evaluation import EvaluationType
|
||||
|
||||
class IEvaluationService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def create_evaluation(
|
||||
self,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
exercise_id: str,
|
||||
eval_type: EvaluationType,
|
||||
task: int
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def begin_evaluation(
|
||||
self,
|
||||
user_id: str, session_id: str, task: int,
|
||||
exercise_id: str, exercise_type: str,
|
||||
solution: any,
|
||||
background_tasks: BackgroundTasks
|
||||
):
|
||||
pass
|
||||
17
ielts_be/services/abc/exam/__init__.py
Normal file
17
ielts_be/services/abc/exam/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from .level import ILevelService
|
||||
from .listening import IListeningService
|
||||
from .writing import IWritingService
|
||||
from .speaking import ISpeakingService
|
||||
from .reading import IReadingService
|
||||
from .grade import IGradeService
|
||||
from .exercises import IExerciseService
|
||||
|
||||
__all__ = [
|
||||
"ILevelService",
|
||||
"IListeningService",
|
||||
"IWritingService",
|
||||
"ISpeakingService",
|
||||
"IReadingService",
|
||||
"IGradeService",
|
||||
"IExerciseService"
|
||||
]
|
||||
33
ielts_be/services/abc/exam/exercises.py
Normal file
33
ielts_be/services/abc/exam/exercises.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class IExerciseService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def generate_multiple_choice(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_blank_space_text(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_reading_passage_utas(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_writing_task(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_speaking_task(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_reading_task(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_listening_task(self, args: Dict, exercise_id: int) -> Dict[str, Any]:
|
||||
pass
|
||||
13
ielts_be/services/abc/exam/grade.py
Normal file
13
ielts_be/services/abc/exam/grade.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
class IGradeService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def grade_short_answers(self, data: Dict):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def calculate_grading_summary(self, extracted_sections: List):
|
||||
pass
|
||||
46
ielts_be/services/abc/exam/level.py
Normal file
46
ielts_be/services/abc/exam/level.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Optional
|
||||
from fastapi import UploadFile
|
||||
|
||||
|
||||
class ILevelService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def generate_exercises(self, dto):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_level_exam(
|
||||
self, number_of_exercises: int = 25, min_timer: int = 25, diagnostic: bool = False
|
||||
) -> Dict:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_level_utas(self):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_custom_level(self, data: Dict):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def upload_level(self, upload: UploadFile, solutions: Optional[UploadFile] = None) -> Dict:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def gen_multiple_choice(
|
||||
self, mc_variant: str, quantity: int, start_id: int = 1 #, *, utas: bool = False, all_exams=None
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def gen_blank_space_text_utas(
|
||||
self, quantity: int, start_id: int, size: int, topic: str
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def gen_reading_passage_utas(
|
||||
self, start_id, mc_quantity: int, topic: Optional[str] #sa_quantity: int,
|
||||
):
|
||||
pass
|
||||
31
ielts_be/services/abc/exam/listening.py
Normal file
31
ielts_be/services/abc/exam/listening.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import queue
|
||||
from abc import ABC, abstractmethod
|
||||
from queue import Queue
|
||||
from typing import Dict, List, Any
|
||||
|
||||
from fastapi import UploadFile
|
||||
|
||||
|
||||
class IListeningService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def generate_listening_dialog( self, section_id: int, topic: str, difficulty: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_listening_question(self, dto):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_mp3(self, dto) -> bytes:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_dialog_from_audio(self, upload: UploadFile):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def import_exam(
|
||||
self, exercises: UploadFile, solutions: UploadFile = None
|
||||
) -> Dict[str, Any] | None:
|
||||
pass
|
||||
17
ielts_be/services/abc/exam/reading.py
Normal file
17
ielts_be/services/abc/exam/reading.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from fastapi import UploadFile
|
||||
|
||||
|
||||
class IReadingService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def import_exam(self, exercises: UploadFile, solutions: UploadFile = None):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_reading_exercises(self, dto):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def generate_reading_passage(self, part: int, topic: str, word_count: int = 800):
|
||||
pass
|
||||
16
ielts_be/services/abc/exam/speaking.py
Normal file
16
ielts_be/services/abc/exam/speaking.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Dict, Optional
|
||||
|
||||
|
||||
class ISpeakingService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def get_speaking_part(
|
||||
self, part: int, topic: str, second_topic: str, difficulty: str
|
||||
) -> Dict:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def grade_speaking_task(self, task: int, items: any) -> Dict:
|
||||
pass
|
||||
|
||||
19
ielts_be/services/abc/exam/writing.py
Normal file
19
ielts_be/services/abc/exam/writing.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import UploadFile
|
||||
|
||||
|
||||
class IWritingService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
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: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def grade_writing_task(self, task: int, question: str, answer: str, attachment: Optional[str]):
|
||||
pass
|
||||
13
ielts_be/services/abc/third_parties/__init__.py
Normal file
13
ielts_be/services/abc/third_parties/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from .stt import ISpeechToTextService
|
||||
from .tts import ITextToSpeechService
|
||||
from .llm import ILLMService
|
||||
from .vid_gen import IVideoGeneratorService
|
||||
from .ai_detector import IAIDetectorService
|
||||
|
||||
__all__ = [
|
||||
"ISpeechToTextService",
|
||||
"ITextToSpeechService",
|
||||
"ILLMService",
|
||||
"IVideoGeneratorService",
|
||||
"IAIDetectorService"
|
||||
]
|
||||
13
ielts_be/services/abc/third_parties/ai_detector.py
Normal file
13
ielts_be/services/abc/third_parties/ai_detector.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, Optional
|
||||
|
||||
|
||||
class IAIDetectorService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def run_detection(self, text: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def _parse_detection(self, response: Dict) -> Optional[Dict]:
|
||||
pass
|
||||
38
ielts_be/services/abc/third_parties/llm.py
Normal file
38
ielts_be/services/abc/third_parties/llm.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Optional, TypeVar, Callable
|
||||
|
||||
from openai.types.chat import ChatCompletionMessageParam
|
||||
from pydantic import BaseModel
|
||||
|
||||
T = TypeVar('T', bound=BaseModel)
|
||||
|
||||
class ILLMService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def prediction(
|
||||
self,
|
||||
model: str,
|
||||
messages: List,
|
||||
fields_to_check: Optional[List[str]],
|
||||
temperature: float,
|
||||
check_blacklisted: bool = True,
|
||||
token_count: int = -1
|
||||
):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def prediction_override(self, **kwargs):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def pydantic_prediction(
|
||||
self,
|
||||
messages: List[ChatCompletionMessageParam],
|
||||
map_to_model: Callable,
|
||||
json_scheme: str,
|
||||
*,
|
||||
model: Optional[str] = None,
|
||||
temperature: Optional[float] = None,
|
||||
max_retries: int = 3
|
||||
) -> List[T] | T | None:
|
||||
pass
|
||||
8
ielts_be/services/abc/third_parties/stt.py
Normal file
8
ielts_be/services/abc/third_parties/stt.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
|
||||
class ISpeechToTextService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def speech_to_text(self, file: bytes):
|
||||
pass
|
||||
22
ielts_be/services/abc/third_parties/tts.py
Normal file
22
ielts_be/services/abc/third_parties/tts.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Union
|
||||
|
||||
|
||||
class ITextToSpeechService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def synthesize_speech(self, text: str, voice: str, engine: str, output_format: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def text_to_speech(self, dialog) -> bytes:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _conversation_to_speech(self, conversation: list):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def _text_to_speech(self, text: str):
|
||||
pass
|
||||
|
||||
22
ielts_be/services/abc/third_parties/vid_gen.py
Normal file
22
ielts_be/services/abc/third_parties/vid_gen.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
|
||||
class IVideoGeneratorService(ABC):
|
||||
|
||||
def __init__(self, avatars: Dict):
|
||||
self._avatars = avatars
|
||||
|
||||
async def get_avatars(self) -> List[Dict]:
|
||||
return [
|
||||
{"name": name, "gender": data["avatar_gender"]}
|
||||
for name, data in self._avatars.items()
|
||||
]
|
||||
|
||||
@abstractmethod
|
||||
async def create_video(self, text: str, avatar: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def poll_status(self, video_id: str):
|
||||
pass
|
||||
7
ielts_be/services/abc/training/__init__.py
Normal file
7
ielts_be/services/abc/training/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from .training import ITrainingService
|
||||
from .kb import IKnowledgeBase
|
||||
|
||||
__all__ = [
|
||||
"ITrainingService",
|
||||
"IKnowledgeBase"
|
||||
]
|
||||
10
ielts_be/services/abc/training/kb.py
Normal file
10
ielts_be/services/abc/training/kb.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from typing import List, Dict
|
||||
|
||||
|
||||
class IKnowledgeBase(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def query_knowledge_base(self, query: str, category: str, top_k: int = 5) -> List[Dict[str, str]]:
|
||||
pass
|
||||
14
ielts_be/services/abc/training/training.py
Normal file
14
ielts_be/services/abc/training/training.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from typing import Dict
|
||||
|
||||
|
||||
class ITrainingService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def fetch_tips(self, context: str, question: str, answer: str, correct_answer: str):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
async def get_training_content(self, training_content: Dict) -> Dict:
|
||||
pass
|
||||
10
ielts_be/services/abc/user.py
Normal file
10
ielts_be/services/abc/user.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from ielts_be.dtos.user_batch import BatchUsersDTO
|
||||
|
||||
|
||||
class IUserService(ABC):
|
||||
|
||||
@abstractmethod
|
||||
async def batch_users(self, batch: BatchUsersDTO):
|
||||
pass
|
||||
Reference in New Issue
Block a user