fix: require manual summary fields before registration

This commit is contained in:
Codex
2026-06-15 16:35:46 +08:00
parent 854e4942ba
commit a7fbe91266
4 changed files with 174 additions and 79 deletions
+81 -72
View File
@@ -975,34 +975,6 @@ def extract_course_summary_from_text(text: str, index: int = 0, known_students:
}
def manual_review_summary(raw: dict, error: Exception) -> dict:
body = str(raw.get("body") or raw.get("content") or "").strip()
source_id = str(raw.get("source_id") or "").strip() or f"manual:{sha1_text(body, 24)}"
return {
"source_id": source_id,
"student": canonical_name(str(raw.get("student") or "").strip()) or "待核对学生",
"date_iso": str(raw.get("date_iso") or raw.get("date") or "").strip(),
"time_range": str(raw.get("time_range") or raw.get("time") or "").strip(),
"duration_minutes": raw.get("duration_minutes"),
"duration": str(raw.get("duration") or "").strip(),
"teacher": canonical_name(str(raw.get("teacher") or "").strip()),
"subject": parse_subject_code(str(raw.get("subject") or "").strip()),
"group": str(raw.get("group") or "").strip(),
"sender": str(raw.get("sender") or "管理后台").strip(),
"sender_id": str(raw.get("sender_id") or "").strip(),
"message_time": str(raw.get("message_time") or "").strip(),
"message_date": str(raw.get("message_date") or "").strip(),
"db": str(raw.get("db") or "").strip(),
"local_id": str(raw.get("local_id") or "").strip(),
"title": str(raw.get("title") or "手工登记课程小结").strip(),
"body": body or str(error),
"recognition_source": "manual_admin",
"confidence": "manual_review",
"teacher_trusted": True,
"remark": f"手工登记待审核:{error}",
}
def normalize_course_summary(raw: dict) -> dict:
student = canonical_name(str(raw.get("student") or "").strip())
teacher = canonical_name(str(raw.get("teacher") or "").strip())
@@ -1510,8 +1482,6 @@ def register_course_summary_texts(
now = datetime.now().isoformat(timespec="seconds")
accounts = read_accounts(accounts_path)
known_students = [account.student for account in accounts]
summaries: list[dict] = []
manual_review_items: list[dict] = []
result = {
"received": len(texts),
"saved": 0,
@@ -1523,60 +1493,99 @@ def register_course_summary_texts(
"items": [],
}
for index, text in enumerate(texts):
raw = extract_course_summary_from_text(text, index, known_students=known_students)
raw: dict | None = None
normalized: dict | None = None
try:
normalize_course_summary(raw)
summaries.append(raw)
except ValueError as exc:
summary = manual_review_summary(raw, exc)
saved = save_course_summary_markdown(summaries_root, summary)
task = create_course_summary_review_task(
tasks_path,
summary,
"",
[str(exc), "手工登记课程小结需人工补全"],
saved_path=str(saved.get("path") or ""),
raw = extract_course_summary_from_text(text, index, known_students=known_students)
normalized = normalize_course_summary(raw)
source_id = normalized["source_id"]
semantic_key = course_summary_semantic_key(normalized)
state = read_course_summary_state(state_path)
seen_source_ids = set(str(item) for item in state.get("seen_source_ids", []))
seen_semantic_keys = set(str(item) for item in state.get("seen_semantic_keys", []))
if source_id in seen_source_ids or semantic_key in seen_semantic_keys:
result["duplicates"] += 1
log_id = append_operation_log(
operation_logs_path,
"course_summary_manual_register",
"duplicate",
source_id=source_id,
student=normalized["student"],
)
result["operation_log_ids"].append(log_id)
result["items"].append({"source_id": source_id, "status": "duplicate"})
continue
reasons, proposed_line = auto_register_reasons(normalized, classnotes_path, accounts_path)
if reasons:
raise ValueError("".join(reasons))
saved = save_course_summary_markdown(summaries_root, normalized)
register_result = register_class_record_lines(classnotes_path, accounts_path, line=proposed_line)
seen_source_ids.add(source_id)
seen_semantic_keys.add(semantic_key)
state["seen_source_ids"] = sorted(seen_source_ids)
state["seen_semantic_keys"] = sorted(seen_semantic_keys)
state.setdefault("batches", []).append(
{
"batch_id": f"manual-{datetime.now().strftime('%Y%m%d%H%M%S')}-{sha1_text(source_id, 8)}",
"received_at": now,
"window": {"source": "admin_register", "submitted_at": now},
"students": [normalized["student"]],
"result": {
"received": 1,
"saved": 1 if saved.get("added") else 0,
"auto_registered": 1,
"review_pending": 0,
"duplicates": 0,
"rejected": 0,
},
}
)
state["batches"] = state["batches"][-200:]
write_course_summary_state(state_path, state)
log_id = append_operation_log(
operation_logs_path,
"course_summary_ingest",
"review",
batch_id=f"manual-{datetime.now().strftime('%Y%m%d%H%M%S')}",
source_id=summary["source_id"],
student=summary["student"],
reasons=[str(exc), "手工登记课程小结需人工补全"],
task_id=task.get("id"),
"course_summary_manual_register",
"auto_registered",
source_id=source_id,
student=normalized["student"],
teacher=normalized.get("teacher", ""),
subject=normalized.get("subject", ""),
proposed_line=proposed_line,
backup_id=str(register_result.get("backup_id") or ""),
saved_path=str(saved.get("path") or ""),
)
result["saved"] += 1 if saved.get("added") else 0
result["review_pending"] += 1
result["auto_registered"] += 1
result["operation_log_ids"].append(log_id)
result["items"].append(
{
"source_id": summary["source_id"],
"status": "review",
"task_id": task.get("id"),
"reasons": [str(exc), "手工登记课程小结需人工补全"],
"source_id": source_id,
"status": "auto_registered",
"backup_id": str(register_result.get("backup_id") or ""),
}
)
except ValueError as exc:
source_id = str((normalized or raw or {}).get("source_id") or f"manual:{sha1_text(text, 24)}")
student = str((normalized or raw or {}).get("student") or "")
log_id = append_operation_log(
operation_logs_path,
"course_summary_manual_register",
"rejected",
source_id=source_id,
student=student,
error=str(exc),
)
result["rejected"] += 1
result["operation_log_ids"].append(log_id)
result["items"].append(
{
"source_id": source_id,
"status": "rejected",
"error": str(exc),
}
)
if not summaries:
return result
ingest_result = ingest_course_summaries(
classnotes_path=classnotes_path,
accounts_path=accounts_path,
tasks_path=tasks_path,
summaries_root=summaries_root,
state_path=state_path,
operation_logs_path=operation_logs_path,
batch_id=f"manual-{datetime.now().strftime('%Y%m%d%H%M%S')}-{sha1_text('|'.join(texts), 8)}",
window={"source": "admin_register", "submitted_at": now},
students=[],
summaries=summaries,
)
for key in ("saved", "auto_registered", "review_pending", "duplicates", "rejected"):
result[key] += int(ingest_result.get(key) or 0)
result["operation_log_ids"].extend(ingest_result.get("operation_log_ids") or [])
result["items"].extend(ingest_result.get("items") or [])
return result