Nuevos cambios en el backend

This commit is contained in:
Mireya Cueto Garrido
2026-05-19 10:21:34 +02:00
parent 02da44fb30
commit ba2507918b
20 changed files with 494 additions and 55 deletions
+48 -14
View File
@@ -3,10 +3,11 @@ import uuid
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.core.errors import NotFoundError
from app.core.errors import ForbiddenError, NotFoundError
from app.core.security import clean_text
from app.models.exam import ExamTemplate, ExportFormat, ExportJob, ExportStatus, Question
from app.schemas.exam import (
ExamHistoryItem,
ExamTemplateCreate,
ExamTemplateRead,
ExportResponse,
@@ -35,8 +36,9 @@ class ExamService:
self.parser = parser or AIQuestionParser()
self.exporter = exporter or MoodleXMLExporter()
def create_template(self, payload: ExamTemplateCreate) -> ExamTemplateRead:
def create_template(self, user_id: uuid.UUID, payload: ExamTemplateCreate) -> ExamTemplateRead:
template = ExamTemplate(
user_id=user_id,
title=clean_text(payload.title, max_length=200),
subject=clean_text(payload.subject, max_length=200),
educational_level=clean_text(payload.educational_level, max_length=120),
@@ -49,37 +51,67 @@ class ExamService:
self.db.refresh(template)
return self._template_read(template)
def list_templates(self) -> list[ExamTemplateRead]:
templates = self.db.scalars(select(ExamTemplate).order_by(ExamTemplate.created_at.desc())).all()
def list_templates(self, user_id: uuid.UUID) -> list[ExamTemplateRead]:
templates = self.db.scalars(
select(ExamTemplate)
.where(ExamTemplate.user_id == user_id)
.order_by(ExamTemplate.created_at.desc())
).all()
return [self._template_read(template) for template in templates]
def get_template(self, template_id: uuid.UUID) -> ExamTemplateRead:
return self._template_read(self._get_template_or_404(template_id))
def list_history(self, user_id: uuid.UUID) -> list[ExamHistoryItem]:
templates = self.db.scalars(
select(ExamTemplate)
.where(ExamTemplate.user_id == user_id)
.order_by(ExamTemplate.updated_at.desc())
).all()
history: list[ExamHistoryItem] = []
for template in templates:
export_jobs = sorted(template.export_jobs, key=lambda job: job.created_at, reverse=True)
history.append(
ExamHistoryItem(
id=template.id,
title=template.title,
subject=template.subject,
educational_level=template.educational_level,
language=template.language,
question_count=len(template.questions),
export_count=len(export_jobs),
last_export_at=export_jobs[0].created_at if export_jobs else None,
created_at=template.created_at,
updated_at=template.updated_at,
)
)
return history
def build_prompt(self, template_id: uuid.UUID, topic_prompt: str) -> PromptResponse:
template = self._get_template_or_404(template_id)
def get_template(self, user_id: uuid.UUID, template_id: uuid.UUID) -> ExamTemplateRead:
return self._template_read(self._get_user_template_or_404(user_id, template_id))
def build_prompt(self, user_id: uuid.UUID, template_id: uuid.UUID, topic_prompt: str) -> PromptResponse:
template = self._get_user_template_or_404(user_id, template_id)
prompt = self.prompt_builder.build_prompt(template, topic_prompt)
return PromptResponse(template_id=template.id, prompt=prompt)
async def generate_with_llm(
self,
user_id: uuid.UUID,
template_id: uuid.UUID,
topic_prompt: str,
llm_client: LLMClient,
) -> ParsedQuestionsResponse:
template = self._get_template_or_404(template_id)
template = self._get_user_template_or_404(user_id, template_id)
prompt = self.prompt_builder.build_prompt(template, topic_prompt)
raw_output = await llm_client.generate(prompt)
questions = self.parser.parse_json(raw_output)
return self._persist_questions(template.id, questions)
def parse_and_persist(self, payload: ParseRequest) -> ParsedQuestionsResponse:
self._get_template_or_404(payload.template_id)
def parse_and_persist(self, user_id: uuid.UUID, payload: ParseRequest) -> ParsedQuestionsResponse:
self._get_user_template_or_404(user_id, payload.template_id)
questions = self.parser.parse(payload.raw_output, payload.input_format)
return self._persist_questions(payload.template_id, questions)
def export(self, template_id: uuid.UUID, export_format: ExportFormat) -> ExportResponse:
template = self._get_template_or_404(template_id)
def export(self, user_id: uuid.UUID, template_id: uuid.UUID, export_format: ExportFormat) -> ExportResponse:
template = self._get_user_template_or_404(user_id, template_id)
questions = list(template.questions)
if not questions:
raise NotFoundError("Template does not contain questions to export")
@@ -126,10 +158,12 @@ class ExamService:
return ParsedQuestionsResponse(questions=[QuestionRead.model_validate(question) for question in persisted])
def _get_template_or_404(self, template_id: uuid.UUID) -> ExamTemplate:
def _get_user_template_or_404(self, user_id: uuid.UUID, template_id: uuid.UUID) -> ExamTemplate:
template = self.db.get(ExamTemplate, template_id)
if template is None:
raise NotFoundError("Exam template not found")
if template.user_id != user_id:
raise ForbiddenError("You do not have access to this exam template")
return template
def _template_read(self, template: ExamTemplate) -> ExamTemplateRead: