Initial MVP for QA asset backend

This commit is contained in:
2026-07-05 17:44:15 +08:00
commit 95b5e09fd4
71 changed files with 6546 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
from typing import Any
REQUIRED_QA_FIELDS = {
"session_id",
"qa_id",
"raw_question",
"normalized_question",
"raw_answer",
"normalized_answer",
"suggested_standard_question",
"suggested_standard_answer",
"answer_person",
"primary_topic",
"problem_tags",
"course_stage",
"audience_tags",
"emotion_intensity",
"risk_level",
"risk_types",
"risk_notes",
"need_desensitization",
"desensitization_status",
"suggested_review_status",
"suggested_to_standard_qa",
"source_timestamp",
"review_notes",
}
def validate_ai_qa_items(payload: Any) -> list[dict[str, Any]]:
if not isinstance(payload, list):
raise ValueError("AI 返回必须是 JSON 数组")
valid_items: list[dict[str, Any]] = []
for index, item in enumerate(payload, start=1):
if not isinstance(item, dict):
raise ValueError(f"{index} 条 AI 结果不是对象")
missing = REQUIRED_QA_FIELDS.difference(item)
if missing:
raise ValueError(f"{index} 条 AI 结果缺少字段: {', '.join(sorted(missing))}")
valid_items.append(item)
return valid_items

View File

@@ -0,0 +1,6 @@
from pathlib import Path
def read_text_file(path: str | Path) -> str:
return Path(path).read_text(encoding="utf-8")

View File

@@ -0,0 +1,20 @@
from datetime import datetime, timezone
def utc_now() -> datetime:
return datetime.now(timezone.utc)
def split_cron(cron: str) -> dict[str, str]:
parts = cron.split()
if len(parts) != 5:
raise ValueError("SCHEDULE_CRON 需要使用 5 段 cron 表达式,例如 0 1 * * *")
minute, hour, day, month, day_of_week = parts
return {
"minute": minute,
"hour": hour,
"day": day,
"month": month,
"day_of_week": day_of_week,
}