91 lines
4.7 KiB
Python
91 lines
4.7 KiB
Python
import shutil
|
|
from pathlib import Path
|
|
|
|
import pymupdf as fitz
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy import select
|
|
|
|
from wisegrade.config import get_settings
|
|
from wisegrade.db import get_db
|
|
from wisegrade.llm import ConsistencyResult, FactResult, ScoreResult
|
|
from wisegrade.main import app
|
|
from wisegrade.models import CourseVersion, CriterionScore, RubricVersion, ScoringBatch, TeacherRevision
|
|
from wisegrade.rag import retrieve
|
|
from wisegrade.scoring import run_batch
|
|
from wisegrade.storage import scan
|
|
|
|
|
|
def fake_embed(texts):
|
|
return [[1.0] + [0.0] * 1023 for _ in texts]
|
|
|
|
|
|
class FakeModel:
|
|
def json_call(self, _prompt, payload, schema, images=None):
|
|
if schema is FactResult:
|
|
return FactResult(topic="自动化实践示例")
|
|
if schema is ConsistencyResult:
|
|
return ConsistencyResult()
|
|
criterion = payload["criterion"]
|
|
evidence = payload["evidence"][0]
|
|
return ScoreResult(criterion_id=criterion["criterion_id"], score=criterion["max_score"] / 2,
|
|
max_score=criterion["max_score"], reason="示例证据支持部分要求",
|
|
evidence=[{"chunk_id": evidence["chunk_id"], "page": evidence["page"],
|
|
"quote": evidence["text"][:min(12, len(evidence["text"]))]}],
|
|
missing_evidence=[], suggestion="补充量化论证", confidence=.7)
|
|
|
|
|
|
def make_pdf(path, title):
|
|
pdf = fitz.open()
|
|
page = pdf.new_page()
|
|
page.insert_text((72, 72), title + " results and analysis for robot control system. " * 4)
|
|
pdf.save(path)
|
|
|
|
|
|
@pytest.mark.integration
|
|
def test_docs_examples_end_to_end(environment, session_factory):
|
|
root = environment / "inbox" / "2026春季第1批" / "1023009006_李傲琦_基于ROS2系统的自瞄移动机器人"
|
|
root.mkdir(parents=True)
|
|
docs = Path(__file__).resolve().parents[2] / "docs"
|
|
for filename in ("阶段报告1.pdf", "阶段报告2.pdf", "阶段报告3.pdf", "自动化专业综合实践报告.pdf"):
|
|
shutil.copy2(docs / filename, root / filename)
|
|
make_pdf(root / "汇报PPT.pdf", "Presentation")
|
|
data = scan("2026春季第1批")
|
|
assert len(data["projects"]) == 1
|
|
scanned = data["projects"][0]
|
|
assert scanned["missing"] == []
|
|
assert next(f for f in scanned["files"] if f["category"] == "presentation")["status"] == "needs_confirmation"
|
|
|
|
def override_db():
|
|
with session_factory() as session:
|
|
yield session
|
|
app.dependency_overrides[get_db] = override_db
|
|
client = TestClient(app)
|
|
try:
|
|
files = [{"relative_path": f["relative_path"], "category": f["category"], "sha256": f["sha256"], "status": "recognized"} for f in scanned["files"]]
|
|
response = client.post("/api/import/confirm", json={"course_version_id": 1, "projects": [{"relative_dir": scanned["relative_dir"],
|
|
"student_no": scanned["student_no"], "name": scanned["name"], "topic": scanned["topic"], "files": files}]})
|
|
assert response.status_code == 200, response.text
|
|
project_id = response.json()["project_ids"][0]
|
|
response = client.post("/api/scoring-batches", json={"course_version_id": 1, "rubric_version_id": 1})
|
|
assert response.status_code == 200, response.text
|
|
batch_id = response.json()["id"]
|
|
run_batch(batch_id, session_factory=session_factory, client_factory=lambda db, batch: FakeModel(), embedder=fake_embed,
|
|
retriever=lambda db, **kwargs: retrieve(db, embedder=fake_embed, **kwargs))
|
|
result = client.get(f"/api/projects/{project_id}/scores?batch_id={batch_id}").json()
|
|
assert result["totals"]["overall"] == 50
|
|
assert all(row["evidence"] and row["evidence"][0]["page"] >= 1 for row in result["rows"])
|
|
assert client.get(result["rows"][0]["evidence"][0]["image_url"]).content[:8] == b"\x89PNG\r\n\x1a\n"
|
|
score_id = result["rows"][0]["score_id"]
|
|
reviewed = client.put(f"/api/criterion-scores/{score_id}/review", json={"score": 20, "comment": "教师核定", "reason": "核查原文"})
|
|
assert reviewed.status_code == 200
|
|
assert reviewed.json()["model_score"] != reviewed.json()["teacher_score"]
|
|
assert len(client.get(f"/api/criterion-scores/{score_id}/revisions").json()) == 1
|
|
excel = client.post("/api/exports/excel", json={"batch_id": batch_id})
|
|
pdf = client.post("/api/exports/project-pdf", json={"batch_id": batch_id, "project_id": project_id})
|
|
assert excel.status_code == pdf.status_code == 200
|
|
assert client.get(f"/api/exports/{excel.json()['id']}/download").content[:2] == b"PK"
|
|
assert client.get(f"/api/exports/{pdf.json()['id']}/download").content[:4] == b"%PDF"
|
|
finally:
|
|
app.dependency_overrides.clear()
|