fix: require manual summary fields before registration
This commit is contained in:
+81
-72
@@ -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
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user