From 47cdfe14780973a820a9d5ca18ff433364fe2b66 Mon Sep 17 00:00:00 2001 From: Carlos-Mesquita Date: Tue, 26 Nov 2024 09:08:12 +0000 Subject: [PATCH] Patched backend eval --- app/configs/dependency_injection.py | 16 ++++++++++++---- app/controllers/abc/grade.py | 2 +- app/controllers/impl/grade.py | 15 ++++++++------- app/dtos/writing.py | 3 ++- app/repositories/impl/file_storage/firebase.py | 3 +-- app/services/abc/evaluation.py | 3 ++- app/services/impl/exam/evaluation.py | 10 +++++++--- app/services/impl/exam/speaking.py | 14 +++++++++++++- app/services/impl/third_parties/whisper.py | 2 +- 9 files changed, 47 insertions(+), 21 deletions(-) diff --git a/app/configs/dependency_injection.py b/app/configs/dependency_injection.py index a468440..a6e934c 100644 --- a/app/configs/dependency_injection.py +++ b/app/configs/dependency_injection.py @@ -10,8 +10,10 @@ from dotenv import load_dotenv from sentence_transformers import SentenceTransformer from app.repositories.impl import * +from app.repositories.impl.document_stores.mongo import MongoDB from app.services.impl import * from app.controllers.impl import * +from app.services.impl.exam.evaluation import EvaluationService load_dotenv() @@ -67,8 +69,8 @@ class DependencyInjector: cred = credentials.Certificate(os.getenv("GOOGLE_APPLICATION_CREDENTIALS")) firebase_token = cred.get_access_token().access_token - self._container.document_store = providers.Object( - AsyncIOMotorClient(os.getenv("MONGODB_URI"))[os.getenv("MONGODB_DB")] + self._container.document_store = providers.Factory( + MongoDB, mongo_db=AsyncIOMotorClient(os.getenv("MONGODB_URI"))[os.getenv("MONGODB_DB")] ) self._container.firebase_instance = providers.Factory( @@ -126,11 +128,17 @@ class DependencyInjector: UserService, document_store=self._container.document_store ) + self._container.evaluation_service = providers.Factory( + EvaluationService, db=self._container.document_store, + writing_service=self._container.writing_service, + speaking_service=self._container.speaking_service + ) + def _setup_controllers(self): + self._container.grade_controller = providers.Factory( GradeController, grade_service=self._container.grade_service, - speaking_service=self._container.speaking_service, - writing_service=self._container.writing_service + evaluation_service=self._container.evaluation_service ) self._container.user_controller = providers.Factory( diff --git a/app/controllers/abc/grade.py b/app/controllers/abc/grade.py index f9c2e64..b767c6e 100644 --- a/app/controllers/abc/grade.py +++ b/app/controllers/abc/grade.py @@ -8,7 +8,7 @@ class IGradeController(ABC): @abstractmethod async def grade_writing_task( - self, session_id: str, exercise_id: str, + self, task: int, dto: any, background_tasks: BackgroundTasks ): diff --git a/app/controllers/impl/grade.py b/app/controllers/impl/grade.py index 0998f35..f80dbca 100644 --- a/app/controllers/impl/grade.py +++ b/app/controllers/impl/grade.py @@ -23,21 +23,22 @@ class GradeController(IGradeController): self._logger = logging.getLogger(__name__) async def grade_writing_task( - self, session_id: str, exercise_id: str, + self, task: int, dto: WritingGradeTaskDTO, background_tasks: BackgroundTasks ): - await self._evaluation_service.create_or_update_evaluation( - dto.sessionId, dto.exercise_id, EvaluationType.WRITING, task + await self._evaluation_service.create_evaluation( + dto.userId, dto.sessionId, dto.exerciseId, EvaluationType.WRITING, task ) await self._evaluation_service.begin_evaluation( - session_id, task, exercise_id, EvaluationType.WRITING, dto, background_tasks + dto.userId, dto.sessionId, task, dto.exerciseId, EvaluationType.WRITING, dto, background_tasks ) return Response(status_code=200) async def grade_speaking_task(self, task: int, form: FormData, background_tasks: BackgroundTasks): answers: Dict[int, Dict] = {} + user_id = form.get("userId") session_id = form.get("sessionId") exercise_id = form.get("exerciseId") @@ -79,12 +80,12 @@ class GradeController(IGradeController): ex_type = EvaluationType.SPEAKING if task == 2 else EvaluationType.SPEAKING_INTERACTIVE - await self._evaluation_service.create_or_update_evaluation( - session_id, exercise_id, ex_type, task + await self._evaluation_service.create_evaluation( + user_id, session_id, exercise_id, ex_type, task ) await self._evaluation_service.begin_evaluation( - session_id, task, exercise_id, ex_type, items, background_tasks + user_id, session_id, task, exercise_id, ex_type, items, background_tasks ) return Response(status_code=200) diff --git a/app/dtos/writing.py b/app/dtos/writing.py index 24ce013..94c662d 100644 --- a/app/dtos/writing.py +++ b/app/dtos/writing.py @@ -2,7 +2,8 @@ from pydantic import BaseModel class WritingGradeTaskDTO(BaseModel): + userId: str sessionId: str + exerciseId: str question: str answer: str - exercise_id: str diff --git a/app/repositories/impl/file_storage/firebase.py b/app/repositories/impl/file_storage/firebase.py index 07c7adf..9450afe 100644 --- a/app/repositories/impl/file_storage/firebase.py +++ b/app/repositories/impl/file_storage/firebase.py @@ -55,8 +55,7 @@ class FirebaseStorage(IFileStorage): if response.status_code == 200: self._logger.info(f"File {source_file_name} uploaded to {self._storage_url}/o/{destination_blob_name}.") - # TODO: Test this - #await self.make_public(destination_blob_name) + await self.make_public(destination_blob_name) file_url = f"{self._storage_url}/o/{destination_blob_name}" return file_url diff --git a/app/services/abc/evaluation.py b/app/services/abc/evaluation.py index 7568777..c7ee386 100644 --- a/app/services/abc/evaluation.py +++ b/app/services/abc/evaluation.py @@ -10,6 +10,7 @@ class IEvaluationService(ABC): @abstractmethod async def create_evaluation( self, + user_id: str, session_id: str, exercise_id: str, eval_type: EvaluationType, @@ -20,7 +21,7 @@ class IEvaluationService(ABC): @abstractmethod async def begin_evaluation( self, - session_id: str, task: int, + user_id: str, session_id: str, task: int, exercise_id: str, exercise_type: str, solution: any, background_tasks: BackgroundTasks diff --git a/app/services/impl/exam/evaluation.py b/app/services/impl/exam/evaluation.py index d7b8a90..12ee185 100644 --- a/app/services/impl/exam/evaluation.py +++ b/app/services/impl/exam/evaluation.py @@ -20,6 +20,7 @@ class EvaluationService(IEvaluationService): async def create_evaluation( self, + user_id: str, session_id: str, exercise_id: str, eval_type: EvaluationType, @@ -28,6 +29,7 @@ class EvaluationService(IEvaluationService): await self._db.save_to_db( "evaluation", { + "user": user_id, "session_id": session_id, "exercise_id": exercise_id, "type": eval_type, @@ -38,20 +40,20 @@ class EvaluationService(IEvaluationService): async def begin_evaluation( self, - session_id: str, task: int, + user_id: str, session_id: str, task: int, exercise_id: str, exercise_type: str, solution: Union[WritingGradeTaskDTO, List[GradeSpeakingItem]], background_tasks: BackgroundTasks ): background_tasks.add_task( self._begin_evaluation, - session_id, task, + user_id, session_id, task, exercise_id, exercise_type, solution ) async def _begin_evaluation( - self, session_id: str, task: int, + self, user_id: str, session_id: str, task: int, exercise_id: str, exercise_type: str, solution: Union[WritingGradeTaskDTO, List[GradeSpeakingItem]] ): @@ -71,6 +73,7 @@ class EvaluationService(IEvaluationService): await self._db.update( "evaluation", { + "user": user_id, "exercise_id": exercise_id, "session_id": session_id, }, @@ -87,6 +90,7 @@ class EvaluationService(IEvaluationService): await self._db.update( "evaluation", { + "user": user_id, "exercise_id": exercise_id, "session_id": session_id }, diff --git a/app/services/impl/exam/speaking.py b/app/services/impl/exam/speaking.py index 7706592..62fb2cc 100644 --- a/app/services/impl/exam/speaking.py +++ b/app/services/impl/exam/speaking.py @@ -1,6 +1,8 @@ import asyncio import logging import os +from uuid import uuid4 + import aiofiles import re import uuid @@ -249,7 +251,17 @@ class SpeakingService(ISpeakingService): response['perfect_answer'] = perfect_answers[0]["answer"] + solutions = [] + for file_name in temp_files: + solutions.append(await self._file_storage.upload_file_firebase_get_url(f'{FilePaths.FIREBASE_SPEAKING_VIDEO_FILES_PATH}{uuid4()}.wav', file_name)) + response["overall"] = self._fix_speaking_overall(response["overall"], response["task_response"]) + response["solutions"] = solutions + if task in {1,3}: + response["answer"] = solutions + else: + response["fullPath"] = solutions[0] + self._log(task, request_id, f'Final response: {response}') return response @@ -266,7 +278,7 @@ class SpeakingService(ISpeakingService): @staticmethod async def save_file(item: GradeSpeakingItem) -> str: - sound_file_name = FilePaths.AUDIO_FILES_PATH + str(uuid.uuid4()) + sound_file_name = "tmp/" + str(uuid.uuid4()) content = await item.answer.read() async with aiofiles.open(sound_file_name, 'wb') as f: await f.write(content) diff --git a/app/services/impl/third_parties/whisper.py b/app/services/impl/third_parties/whisper.py index d74dedc..3ef4a08 100644 --- a/app/services/impl/third_parties/whisper.py +++ b/app/services/impl/third_parties/whisper.py @@ -26,7 +26,7 @@ class OpenAIWhisper(ISpeechToTextService): self._is_closed = False for i in range(num_models): - self._models[i] = whisper.load_model(self._model_name) + self._models[i] = whisper.load_model(self._model_name, in_memory=True) self._executor = ThreadPoolExecutor( max_workers=num_models,