diff --git a/app/data.py b/app/data.py
index ebdf295..ccef0c9 100644
--- a/app/data.py
+++ b/app/data.py
@@ -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
diff --git a/app/static/admin.html b/app/static/admin.html
index 7b60324..1fdd797 100644
--- a/app/static/admin.html
+++ b/app/static/admin.html
@@ -319,6 +319,6 @@
-
+