fix: improve import, evidence indexing and material-scoped grading
Preserve document revisions and evidence, harden indexing and export behavior, add explicit material selection and direct-folder import, validate model JSON schemas with safe error messages, and retain student selection while loading scoring data.
This commit is contained in:
@@ -4,11 +4,11 @@ from pathlib import Path
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill
|
||||
from sqlalchemy import select
|
||||
from weasyprint import HTML
|
||||
|
||||
from .config import get_settings
|
||||
from .evidence import POLICY_VERSION
|
||||
from .knowledge_pages import evidence_links
|
||||
from .models import (CriterionScore, ExportTask, Project, ScoreEvidence, ScoringBatch, Student, SubmissionFile)
|
||||
from .models import (CriterionScore, ExportTask, KnowledgeDocument, KnowledgePage, Project, ScoreEvidence, ScoringBatch, Student, SubmissionFile)
|
||||
from .rules import totals
|
||||
|
||||
#: Teacher-facing wording for a criterion status, shared by exports and the API.
|
||||
@@ -43,6 +43,20 @@ def project_result(db, batch: ScoringBatch, project: Project):
|
||||
CriterionScore.project_id == project.id)).all()
|
||||
by_id = {score.criterion_id: score for score in scores}
|
||||
criteria = batch.rubric_snapshot["criteria"]
|
||||
all_evidence = db.scalars(select(ScoreEvidence).where(ScoreEvidence.score_id.in_([s.id for s in scores]))).all() if scores else []
|
||||
evidence_by_score = {}
|
||||
for item in all_evidence:
|
||||
evidence_by_score.setdefault(item.score_id, []).append(item)
|
||||
file_ids = {item.submission_file_id for item in all_evidence if item.submission_file_id}
|
||||
file_names = dict(db.execute(select(SubmissionFile.id, SubmissionFile.relative_path).where(SubmissionFile.id.in_(file_ids))).all()) if file_ids else {}
|
||||
# Keep canonical source entities alive for this result, so page_links uses the
|
||||
# session identity map instead of issuing a query for every quotation.
|
||||
doc_ids = {item.document_id for item in all_evidence if item.document_id}
|
||||
documents = db.scalars(select(KnowledgeDocument).where(KnowledgeDocument.id.in_(doc_ids))).all() if doc_ids else []
|
||||
retired_ids = {doc.id for doc in documents if doc.status == "superseded"}
|
||||
cited_pages = {item.page for item in all_evidence}
|
||||
pages = db.scalars(select(KnowledgePage).where(KnowledgePage.document_id.in_(doc_ids),
|
||||
KnowledgePage.page.in_(cited_pages))).all() if doc_ids else []
|
||||
totals_ = totals({key: score.final_score for key, score in by_id.items()}, criteria, batch.rubric_snapshot["weights"])
|
||||
rows = []
|
||||
def evidence_dict(item, links):
|
||||
@@ -53,12 +67,13 @@ def project_result(db, batch: ScoringBatch, project: Project):
|
||||
"source_role": item.source_role or "content",
|
||||
# A quotation saved before the evidence policy existed is labelled as a
|
||||
# historical citation and never presented as report body evidence.
|
||||
"historical": bool(item.historical),
|
||||
"document": db.get(SubmissionFile, item.submission_file_id).relative_path if item.submission_file_id else "课程资料",
|
||||
**links}
|
||||
"historical": bool(item.historical) or item.document_id in retired_ids
|
||||
or batch.rubric_snapshot.get("evidence_plan", {}).get("version") != POLICY_VERSION,
|
||||
"document": file_names.get(item.submission_file_id, "来源材料") if item.submission_file_id else "课程资料",
|
||||
"url": links["url"], "image_url": links["image_url"]}
|
||||
for criterion in criteria:
|
||||
score = by_id.get(criterion["criterion_id"])
|
||||
evidence = db.scalars(select(ScoreEvidence).where(ScoreEvidence.score_id == score.id)).all() if score else []
|
||||
evidence = evidence_by_score.get(score.id, []) if score else []
|
||||
rows.append({"criterion": criterion, "score_id": score.id if score else None,
|
||||
"model_score": score.model_score if score else None, "teacher_score": score.teacher_score if score else None,
|
||||
"final_score": score.final_score if score else None,
|
||||
@@ -124,7 +139,7 @@ def export_excel(db, batch_id: int):
|
||||
|
||||
|
||||
def _html_report(result, batch):
|
||||
esc = lambda value: escape(str(value or ""))
|
||||
esc = lambda value: escape("" if value is None else str(value))
|
||||
rows = []
|
||||
for row in result["rows"]:
|
||||
criterion = row["criterion"]
|
||||
@@ -170,6 +185,7 @@ def export_project_pdf(db, batch_id: int, project_id: int):
|
||||
db.flush()
|
||||
path = root / f"batch-{batch_id}-project-{project_id}-{task.id}.pdf"
|
||||
try:
|
||||
from weasyprint import HTML
|
||||
HTML(string=_html_report(project_result(db, batch, project), batch)).write_pdf(path)
|
||||
task.path, task.status = str(path), "completed"
|
||||
except Exception as exc:
|
||||
|
||||
Reference in New Issue
Block a user