fix: 批量匹配跳过画像待补录教师 + render-html 按行重建 + 金标准 fixtures 业务化(P0+P1)
- run_match 新增 skip_incomplete:批量缺省跳过画像不完整教师并记录 skipped,指定单教师仍 PROFILE_INCOMPLETE;汇总页出"画像待补录"行 - render-html 补 --report-id 行上下文(inputMapping $row.$pk),CLI 容错解析回退最近 10 份 - report_service 日志改容错 _log(),修复未 setup 时单跑测试崩溃的顺序依赖 - fixtures 替换为教师画像/赛道/期望结论金标准样例,新增 sample_tracks.json - 新增 4 个批量跳过用例(314 项,除 3 个已知 jsonschema 环境失败外全绿) - tests/README 增补本机无共享 runtime 的测试方式;TUTORIAL/ACTIONS.md 同步表述
This commit is contained in:
@@ -247,8 +247,20 @@ def _write_report(result: dict[str, Any], batch_no: str) -> str:
|
||||
return write_report_for_kernel(result=result, batch_no=batch_no)
|
||||
|
||||
|
||||
def run_match(teachers_raw: list[dict[str, Any]], tracks: list[dict[str, Any]], season: str, *, batch_no: str = "") -> dict[str, Any]:
|
||||
"""匹配内核:逐教师匹配 → 写库 → 生成建议书(多人时另出汇总页)。"""
|
||||
def run_match(
|
||||
teachers_raw: list[dict[str, Any]],
|
||||
tracks: list[dict[str, Any]],
|
||||
season: str,
|
||||
*,
|
||||
batch_no: str = "",
|
||||
skip_incomplete: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
"""匹配内核:逐教师匹配 → 写库 → 生成建议书(多人时另出汇总页)。
|
||||
|
||||
skip_incomplete=True(批量缺省):画像不完整(E1)的教师被跳过并记入
|
||||
``skipped``,不中断批次;skip_incomplete=False(指定单教师):直接抛
|
||||
ValueError,由 CLI 映射 PROFILE_INCOMPLETE。
|
||||
"""
|
||||
from service.report_service import build_batch_brief
|
||||
|
||||
log = _log()
|
||||
@@ -263,11 +275,21 @@ def run_match(teachers_raw: list[dict[str, Any]], tracks: list[dict[str, Any]],
|
||||
log.info("match_kernel_start batch_no=%s teachers=%s tracks=%s season=%s stage=kernel", batch_no, len(teachers_raw), len(tracks), season)
|
||||
|
||||
results = []
|
||||
skipped: list[dict[str, str]] = []
|
||||
conn = get_conn()
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
for teacher_raw in teachers_raw:
|
||||
result = match_teacher(teacher_raw, tracks, season)
|
||||
try:
|
||||
result = match_teacher(teacher_raw, tracks, season)
|
||||
except ValueError as exc:
|
||||
if not skip_incomplete:
|
||||
raise
|
||||
raw_name = str((teacher_raw or {}).get("teacherName") or (teacher_raw or {}).get("teacher_name") or "").strip() or "未命名教师"
|
||||
skipped.append({"teacher_name": raw_name, "reason": str(exc)})
|
||||
if log:
|
||||
log.warning("match_teacher_skipped teacher=%s reason=%s stage=kernel", raw_name, exc)
|
||||
continue
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO match_reports
|
||||
@@ -296,7 +318,7 @@ def run_match(teachers_raw: list[dict[str, Any]], tracks: list[dict[str, Any]],
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
brief_file = build_batch_brief(batch_no=batch_no, results=results, season=season)
|
||||
brief_file = build_batch_brief(batch_no=batch_no, results=results, season=season, skipped=skipped)
|
||||
tier_counts: dict[str, int] = {}
|
||||
for result in results:
|
||||
for tier, entries in result["tiers"].items():
|
||||
@@ -307,13 +329,19 @@ def run_match(teachers_raw: list[dict[str, Any]], tracks: list[dict[str, Any]],
|
||||
"batch_no": batch_no,
|
||||
"season": season,
|
||||
"count": len(results),
|
||||
"skipped": skipped,
|
||||
"tier_counts": tier_counts,
|
||||
"brief_file": brief_file,
|
||||
"disclaimer": "推荐仅供参考,申报决策请结合个人规划与学院统筹。",
|
||||
"reports": results,
|
||||
}
|
||||
if log:
|
||||
log.info("match_kernel_done batch_no=%s count=%s stage=kernel", batch_no, len(results))
|
||||
log.info(
|
||||
"match_kernel_done batch_no=%s count=%s skipped=%s stage=kernel",
|
||||
batch_no,
|
||||
len(results),
|
||||
len(skipped),
|
||||
)
|
||||
return payload
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user