"""答题 / 练习记录,以及 AI 调用审计。""" import enum from sqlalchemy import Boolean, ForeignKey, Integer, String, Text from sqlalchemy import Enum as SAEnum from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.types import JSON from app.models.base import new_uuid from app.db import Base, TimestampMixin class JudgedBy(str, enum.Enum): auto = "auto" # 客观题本地判分 ai = "ai" # 主观题 AI 判分 self_ = "self" # 用户自评 class PracticeRecord(Base, TimestampMixin): __tablename__ = "practice_records" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) user_id: Mapped[str] = mapped_column( ForeignKey("users.id", ondelete="CASCADE"), index=True ) question_id: Mapped[str] = mapped_column( ForeignKey("questions.id", ondelete="CASCADE"), index=True ) user_answer: Mapped[list | None] = mapped_column(JSON, nullable=True) is_correct: Mapped[bool | None] = mapped_column(Boolean, nullable=True) judged_by: Mapped[JudgedBy] = mapped_column(SAEnum(JudgedBy), default=JudgedBy.auto) ai_feedback_markdown: Mapped[str | None] = mapped_column(Text, nullable=True) class AiGeneration(Base, TimestampMixin): """记录每次 AI 调用,便于复用缓存、成本观察、排查。""" __tablename__ = "ai_generations" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=new_uuid) user_id: Mapped[str] = mapped_column( ForeignKey("users.id", ondelete="CASCADE"), index=True ) question_id: Mapped[str | None] = mapped_column(String(36), nullable=True) task: Mapped[str] = mapped_column(String(32)) # extract/judge/summarize/explain model: Mapped[str | None] = mapped_column(String(128), nullable=True) request_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True) response_tokens: Mapped[int | None] = mapped_column(Integer, nullable=True) content_markdown: Mapped[str | None] = mapped_column(Text, nullable=True)