fix: share precise scoring failure labels across API chat and exports

This commit is contained in:
2026-10-18 12:16:04 +08:00
parent 000638718c
commit ba5a6952bb
3 changed files with 47 additions and 6 deletions
+21 -4
View File
@@ -1,5 +1,6 @@
from html import escape
from pathlib import Path
import re
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill
@@ -18,7 +19,7 @@ STATUS_LABELS = {
"reviewed": "教师已复核",
"needs_review": "待教师复核",
"unscorable": "材料缺失或解析失败",
"failed": "模型调用失败",
"failed": "评分失败",
}
PAGE_TYPE_LABELS = {
"cover": "封面", "abstract": "摘要", "toc": "目录", "body": "正文",
@@ -38,6 +39,21 @@ def page_type_label(value) -> str:
return PAGE_TYPE_LABELS.get(str(value or "unknown"), "未分类页面")
def criterion_status_label(status: str, error: str = "") -> str:
"""One description for API, chat and exported feedback, including old errors."""
if status != "failed":
return STATUS_LABELS.get(status, status)
# The client wraps transport failures in "模型请求或JSON校验失败" too:
# inspect the concrete cause before that generic wrapper.
if re.search(r"ConnectError|Timeout|Network|无法连接|请求超时", error, re.IGNORECASE):
return "模型连接失败"
if re.search(r"HTTP\s*\d{3}|未配置.*(?:模型|Key)|未配置或无法连接", error, re.IGNORECASE):
return "模型请求失败"
if re.search(r"模型证据|target_id|评分项或满分|JSON校验|ValidationError", error):
return "模型输出校验失败"
return STATUS_LABELS["failed"]
def project_result(db, batch: ScoringBatch, project: Project):
scores = db.scalars(select(CriterionScore).where(CriterionScore.batch_id == batch.id,
CriterionScore.project_id == project.id)).all()
@@ -81,6 +97,7 @@ def project_result(db, batch: ScoringBatch, project: Project):
"model_comment": score.model_comment if score else "", "teacher_comment": score.teacher_comment if score else None,
"missing_evidence": score.missing_evidence if score else [], "suggestion": score.suggestion if score else "",
"status": score.status if score else "pending", "error": score.error if score else "",
"status_label": criterion_status_label(score.status, score.error or "") if score else STATUS_LABELS["pending"],
"evidence_gaps": (score.evidence_gaps or []) if score else [],
"evidence": [evidence_dict(item, evidence_links(db, item)) for item in evidence]})
student = db.get(Student, project.student_id)
@@ -152,12 +169,12 @@ def _html_report(result, batch):
missing = "、".join(row["missing_evidence"] or [])
gaps = ";".join(f"{gap.get('target_label')}(检索范围:{'、'.join(page_type_label(t) for t in gap.get('searched_page_types') or []) or '正文'})"
for gap in row.get("evidence_gaps") or [])
review = "本项缺少正文证据,已转教师复核。" if row["status"] == "needs_review" else ""
review = "本项证据尚不足以自动评分,已转教师复核。" if row["status"] == "needs_review" else ""
rows.append(f"<section><h3>{esc(criterion['name'])}({esc(row['final_score'])} / {criterion['max_score']})</h3>"
f"<p>模型原始分:{esc(row['model_score'])};教师修改分:{esc(row['teacher_score'])};状态:{esc(STATUS_LABELS.get(row['status'], row['status']))}</p>"
f"<p>模型原始分:{esc(row['model_score'])};教师修改分:{esc(row['teacher_score'])};状态:{esc(criterion_status_label(row['status'], row.get('error') or ''))}</p>"
f"<p>模型评语:{esc(row['model_comment'])}</p><p>教师评语:{esc(row['teacher_comment'])}</p>"
f"<p>{esc(review)}</p>"
f"<p>缺失证据:{esc(missing)}</p><p>缺正文证据的目标:{esc(gaps)}</p>"
f"<p>缺失证据:{esc(missing)}</p><p>待核对的证据目标:{esc(gaps)}</p>"
f"<p>建议:{esc(row['suggestion'])}</p><p>异常:{esc(row['error'])}</p>"
f"<ul>{evidences}</ul></section>")
totals_ = result["totals"]