Brushed up the backend, added writing task 1 academic prompt gen and grading ENCOA-274

This commit is contained in:
Carlos-Mesquita
2024-12-10 22:24:40 +00:00
parent 68cab80851
commit 6982068864
167 changed files with 1411 additions and 1229 deletions

15
ielts_be/api/__init__.py Normal file
View File

@@ -0,0 +1,15 @@
from fastapi import APIRouter
from .training import training_router
from .user import user_router
from .exam import exam_router
router = APIRouter(prefix="/api", tags=["Home"])
@router.get('/healthcheck')
async def healthcheck():
return {"healthy": True}
router.include_router(training_router, prefix="/training", tags=["Training"])
router.include_router(user_router, prefix="/user", tags=["Users"])
router.include_router(exam_router)

View File

@@ -0,0 +1,16 @@
from fastapi import APIRouter
from .listening import listening_router
from .reading import reading_router
from .speaking import speaking_router
from .writing import writing_router
from .level import level_router
from .grade import grade_router
exam_router = APIRouter()
exam_router.include_router(listening_router, prefix="/listening", tags=["Listening"])
exam_router.include_router(reading_router, prefix="/reading", tags=["Reading"])
exam_router.include_router(speaking_router, prefix="/speaking", tags=["Speaking"])
exam_router.include_router(writing_router, prefix="/writing", tags=["Writing"])
exam_router.include_router(level_router, prefix="/level", tags=["Level"])
exam_router.include_router(grade_router, prefix="/grade", tags=["Grade"])

View File

@@ -0,0 +1,65 @@
from dependency_injector.wiring import inject, Provide
from fastapi import APIRouter, Depends, Path, Request, BackgroundTasks
from ielts_be.controllers import IGradeController
from ielts_be.dtos.writing import WritingGradeTaskDTO
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
controller = "grade_controller"
grade_router = APIRouter()
@grade_router.post(
'/writing/{task}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def grade_writing_task(
data: WritingGradeTaskDTO,
background_tasks: BackgroundTasks,
task: int = Path(..., ge=1, le=2),
grade_controller: IGradeController = Depends(Provide[controller])
):
return await grade_controller.grade_writing_task(task, data, background_tasks)
@grade_router.post(
'/speaking/{task}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def grade_speaking_task(
request: Request,
background_tasks: BackgroundTasks,
task: int = Path(..., ge=1, le=3),
grade_controller: IGradeController = Depends(Provide[controller])
):
form = await request.form()
return await grade_controller.grade_speaking_task(task, form, background_tasks)
@grade_router.post(
'/summary',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def grading_summary(
request: Request,
grade_controller: IGradeController = Depends(Provide[controller])
):
data = await request.json()
return await grade_controller.grading_summary(data)
@grade_router.post(
'/short_answers',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def grade_short_answers(
request: Request,
grade_controller: IGradeController = Depends(Provide[controller])
):
data = await request.json()
return await grade_controller.grade_short_answers(data)

View File

@@ -0,0 +1,67 @@
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, UploadFile, Request
from ielts_be.dtos.level import LevelExercisesDTO
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.controllers import ILevelController
controller = "level_controller"
level_router = APIRouter()
@level_router.post(
'/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_exercises(
dto: LevelExercisesDTO,
level_controller: ILevelController = Depends(Provide[controller])
):
return await level_controller.generate_exercises(dto)
@level_router.get(
'/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def get_level_exam(
level_controller: ILevelController = Depends(Provide[controller])
):
return await level_controller.get_level_exam()
@level_router.get(
'/utas',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def get_level_utas(
level_controller: ILevelController = Depends(Provide[controller])
):
return await level_controller.get_level_utas()
@level_router.post(
'/import/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def import_level(
exercises: UploadFile,
solutions: UploadFile = None,
level_controller: ILevelController = Depends(Provide[controller])
):
return await level_controller.upload_level(exercises, solutions)
@level_router.post(
'/custom/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def custom_level(
request: Request,
level_controller: ILevelController = Depends(Provide[controller])
):
data = await request.json()
return await level_controller.get_custom_level(data)

View File

@@ -0,0 +1,63 @@
import random
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Path, Query, UploadFile
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.controllers import IListeningController
from ielts_be.configs.constants import EducationalContent
from ielts_be.dtos.listening import GenerateListeningExercises, Dialog
controller = "listening_controller"
listening_router = APIRouter()
@listening_router.post(
'/import',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def upload(
exercises: UploadFile,
solutions: UploadFile = None,
listening_controller: IListeningController = Depends(Provide[controller])
):
return await listening_controller.import_exam(exercises, solutions)
@listening_router.get(
'/{section}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_listening_dialog(
section: int = Path(..., ge=1, le=4),
difficulty: str = Query(default=None),
topic: str = Query(default=None),
listening_controller: IListeningController = Depends(Provide[controller])
):
difficulty = random.choice(EducationalContent.DIFFICULTIES) if not difficulty else difficulty
topic = random.choice(EducationalContent.TOPICS) if not topic else topic
return await listening_controller.generate_listening_dialog(section, topic, difficulty)
@listening_router.post(
'/media',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_mp3(
dto: Dialog,
listening_controller: IListeningController = Depends(Provide[controller])
):
return await listening_controller.generate_mp3(dto)
@listening_router.post(
'/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_listening_exercise(
dto: GenerateListeningExercises,
listening_controller: IListeningController = Depends(Provide[controller])
):
return await listening_controller.get_listening_question(dto)

View File

@@ -0,0 +1,51 @@
import random
from typing import Optional
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Path, Query, UploadFile
from ielts_be.configs.constants import EducationalContent
from ielts_be.dtos.reading import ReadingDTO
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.controllers import IReadingController
controller = "reading_controller"
reading_router = APIRouter()
@reading_router.post(
'/import',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def upload(
exercises: UploadFile,
solutions: UploadFile = None,
reading_controller: IReadingController = Depends(Provide[controller])
):
return await reading_controller.import_exam(exercises, solutions)
@reading_router.get(
'/{passage}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_passage(
topic: Optional[str] = Query(None),
word_count: Optional[int] = Query(None),
passage: int = Path(..., ge=1, le=3),
reading_controller: IReadingController = Depends(Provide[controller])
):
topic = random.choice(EducationalContent.TOPICS) if not topic else topic
return await reading_controller.generate_reading_passage(passage, topic, word_count)
@reading_router.post(
'/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_reading(
dto: ReadingDTO,
reading_controller: IReadingController = Depends(Provide[controller])
):
return await reading_controller.generate_reading_exercises(dto)

View File

@@ -0,0 +1,71 @@
import random
from typing import Optional
from dependency_injector.wiring import inject, Provide
from fastapi import APIRouter, Path, Query, Depends
from ielts_be.dtos.speaking import Video
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.configs.constants import EducationalContent
from ielts_be.controllers import ISpeakingController
controller = "speaking_controller"
speaking_router = APIRouter()
@speaking_router.post(
'/media',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_video(
video: Video,
speaking_controller: ISpeakingController = Depends(Provide[controller])
):
return await speaking_controller.generate_video(video.text, video.avatar)
@speaking_router.get(
'/media/{vid_id}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def poll_video(
vid_id: str = Path(...),
speaking_controller: ISpeakingController = Depends(Provide[controller])
):
return await speaking_controller.poll_video(vid_id)
@speaking_router.get(
'/avatars',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def get_avatars(
speaking_controller: ISpeakingController = Depends(Provide[controller])
):
return await speaking_controller.get_avatars()
@speaking_router.get(
'/{task}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def get_speaking_task(
task: int = Path(..., ge=1, le=3),
topic: Optional[str] = Query(None),
first_topic: Optional[str] = Query(None),
second_topic: Optional[str] = Query(None),
difficulty: str = Query(default=random.choice(EducationalContent.DIFFICULTIES)),
speaking_controller: ISpeakingController = Depends(Provide[controller])
):
if not second_topic:
topic_or_first_topic = topic if topic else random.choice(EducationalContent.MTI_TOPICS)
else:
topic_or_first_topic = first_topic if first_topic else random.choice(EducationalContent.MTI_TOPICS)
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

@@ -0,0 +1,42 @@
import random
from dependency_injector.wiring import inject, Provide
from fastapi import APIRouter, Path, Query, Depends, UploadFile, File
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.configs.constants import EducationalContent
from ielts_be.controllers import IWritingController
controller = "writing_controller"
writing_router = APIRouter()
@writing_router.post(
'/{task}/attachment',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_writing_academic(
task: int = Path(..., ge=1, le=2),
file: UploadFile = File(...),
difficulty: str = Query(default=None),
writing_controller: IWritingController = Depends(Provide[controller])
):
difficulty = random.choice(EducationalContent.DIFFICULTIES) if not difficulty else difficulty
return await writing_controller.get_writing_task_academic_question(task, file, difficulty)
@writing_router.get(
'/{task}',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def generate_writing(
task: int = Path(..., ge=1, le=2),
difficulty: str = Query(default=None),
topic: str = Query(default=None),
writing_controller: IWritingController = Depends(Provide[controller])
):
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)

9
ielts_be/api/home.py Normal file
View File

@@ -0,0 +1,9 @@
from fastapi import APIRouter
home_router = APIRouter()
@home_router.get(
'/healthcheck'
)
async def healthcheck():
return {"healthy": True}

34
ielts_be/api/training.py Normal file
View File

@@ -0,0 +1,34 @@
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends, Request
from ielts_be.dtos.training import FetchTipsDTO
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.controllers import ITrainingController
controller = "training_controller"
training_router = APIRouter()
@training_router.post(
'/tips',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def get_reading_passage(
data: FetchTipsDTO,
training_controller: ITrainingController = Depends(Provide[controller])
):
return await training_controller.fetch_tips(data)
@training_router.post(
'/',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def training_content(
request: Request,
training_controller: ITrainingController = Depends(Provide[controller])
):
data = await request.json()
return await training_controller.get_training_content(data)

21
ielts_be/api/user.py Normal file
View File

@@ -0,0 +1,21 @@
from dependency_injector.wiring import Provide, inject
from fastapi import APIRouter, Depends
from ielts_be.dtos.user_batch import BatchUsersDTO
from ielts_be.middlewares import Authorized, IsAuthenticatedViaBearerToken
from ielts_be.controllers import IUserController
controller = "user_controller"
user_router = APIRouter()
@user_router.post(
'/import',
dependencies=[Depends(Authorized([IsAuthenticatedViaBearerToken]))]
)
@inject
async def batch_import(
batch: BatchUsersDTO,
user_controller: IUserController = Depends(Provide[controller])
):
return await user_controller.batch_import(batch)