Files
xsk-education-management/app/app/routers/ingest.py
T

116 lines
4.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from __future__ import annotations
from fastapi import APIRouter, Depends, HTTPException
from ..auth import verify_ingest_token
from ..ai_register import preview_register
from ..config import (
ACCOUNTS_PATH,
ADMIN_TASKS_PATH,
CLASSNOTES_PATH,
COURSE_SUMMARIES_ROOT,
COURSE_SUMMARY_STATE_PATH,
OPERATION_LOGS_PATH,
write_lock,
)
from ..data import ingest_course_summaries
from ..schemas import CourseSummaryIngestPayload
router = APIRouter()
def _summary_text(raw: dict) -> str:
parts = []
mapping = [
("student", "学生"),
("date_iso", "日期"),
("date", "日期"),
("time_range", "时间"),
("raw_time", "时间"),
("teacher", "老师"),
("subject", "科目"),
]
for key, label in mapping:
value = str(raw.get(key) or "").strip()
if value:
parts.append(f"{label}{value}")
body = str(raw.get("body") or raw.get("content") or "").strip()
if body:
parts.append("小结:")
parts.append(body)
return "\n".join(parts)
def _needs_script_summary(raw: dict) -> bool:
required = ["student", "teacher", "subject"]
if any(not str(raw.get(key) or "").strip() for key in required):
return True
if not str(raw.get("date_iso") or raw.get("date") or raw.get("class_date") or "").strip():
return True
if not str(raw.get("time_range") or raw.get("raw_time") or raw.get("time") or "").strip():
return True
return False
def _standard_text_to_raw(text: str, original: dict) -> dict:
from ..data import extract_course_summary_from_text, normalize_course_summary
raw = extract_course_summary_from_text(text, known_students=[])
normalized = normalize_course_summary({**original, **raw})
return {**original, **normalized}
def _preprocess_summaries_locally(summaries: list[dict]) -> list[dict]:
processed: list[dict] = []
for raw in summaries:
if not _needs_script_summary(raw):
processed.append(raw)
continue
try:
preview = preview_register(register_type="course_summary", text=_summary_text(raw))
except ValueError as exc:
processed.append({**raw, "ai_used": False, "ai_questions": [str(exc)]})
continue
if preview.get("status") == "ready" and preview.get("standard_lines"):
try:
updated = _standard_text_to_raw(str(preview["standard_lines"][0]), raw)
processed.append({
**updated,
"ai_used": False,
"ai_summary": str(preview.get("summary") or ""),
})
except ValueError as exc:
processed.append({**raw, "ai_used": False, "ai_questions": [str(exc)]})
continue
questions = [str(item) for item in preview.get("questions") or [] if str(item)]
processed.append({
**raw,
"ai_used": False,
"ai_summary": str(preview.get("summary") or ""),
"ai_questions": questions or ["脚本未能补齐课程小结信息"],
})
return processed
@router.post("/api/ingest/course-summaries")
def ingest_course_summary_batch(payload: CourseSummaryIngestPayload, _user: str = Depends(verify_ingest_token)):
try:
summaries = _preprocess_summaries_locally([item.dict() for item in payload.summaries])
with write_lock:
result = ingest_course_summaries(
classnotes_path=CLASSNOTES_PATH,
accounts_path=ACCOUNTS_PATH,
tasks_path=ADMIN_TASKS_PATH,
summaries_root=COURSE_SUMMARIES_ROOT,
state_path=COURSE_SUMMARY_STATE_PATH,
operation_logs_path=OPERATION_LOGS_PATH,
batch_id=payload.batch_id,
window=payload.window,
students=payload.students,
summaries=summaries,
)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
return {"ok": True, **result}