78 lines
5.5 KiB
Python
78 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from decimal import Decimal
|
|
|
|
from sqlalchemy import BigInteger, DateTime, ForeignKey, Integer, JSON, Numeric, String, Text, UniqueConstraint
|
|
from sqlalchemy.orm import Mapped, mapped_column, relationship
|
|
|
|
from app.db.base import Base
|
|
from app.models.mixins import TimestampMixin
|
|
|
|
BIGINT_PK = BigInteger().with_variant(Integer, "sqlite")
|
|
|
|
|
|
class TrainingRecord(TimestampMixin, Base):
|
|
"""训练记录表:完整完成问诊、诊断、治疗和评价后写入长期记录。"""
|
|
|
|
__tablename__ = "training_record"
|
|
|
|
id: Mapped[int] = mapped_column(BIGINT_PK, primary_key=True, autoincrement=True, comment="训练记录ID")
|
|
training_mode: Mapped[str] = mapped_column(String(50), nullable=False, index=True, comment="训练模式")
|
|
case_type: Mapped[str] = mapped_column(String(30), nullable=False, index=True, comment="病例/训练类型")
|
|
start_time: Mapped[datetime] = mapped_column(DateTime, nullable=False, comment="训练开始时间")
|
|
end_time: Mapped[datetime | None] = mapped_column(DateTime, comment="训练结束时间")
|
|
duration_seconds: Mapped[int | None] = mapped_column(Integer, comment="训练持续秒数")
|
|
total_score: Mapped[Decimal | None] = mapped_column(Numeric(5, 2), comment="总分")
|
|
ai_score: Mapped[Decimal | None] = mapped_column(Numeric(5, 2), comment="AI评分")
|
|
teacher_score: Mapped[Decimal | None] = mapped_column(Numeric(5, 2), comment="教师评分")
|
|
evaluation_level: Mapped[str] = mapped_column(String(20), nullable=False, default="", comment="评价等级")
|
|
status: Mapped[str] = mapped_column(String(30), nullable=False, index=True, comment="记录状态")
|
|
feedback: Mapped[str] = mapped_column(Text, nullable=False, default="", comment="总体反馈")
|
|
thinking_chain: Mapped[str] = mapped_column(Text, nullable=False, default="", comment="诊断循证与评分依据摘要")
|
|
diagnosis_path: Mapped[str] = mapped_column(Text, nullable=False, default="", comment="诊断路径摘要")
|
|
wrong_points: Mapped[list] = mapped_column(JSON, nullable=False, default=list, comment="错误点/扣分点")
|
|
missed_questions: Mapped[list] = mapped_column(JSON, nullable=False, default=list, comment="遗漏问题")
|
|
recommendation_result: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict, comment="改进建议和导出结果")
|
|
ai_feedback_structured: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict, comment="AI结构化评价")
|
|
osce_station_score: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict, comment="OSCE站点评分")
|
|
interruption_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, comment="中断次数")
|
|
emotion_analysis: Mapped[dict] = mapped_column(JSON, nullable=False, default=dict, comment="情绪分析")
|
|
prompt_version: Mapped[str] = mapped_column(String(50), nullable=False, default="v1", comment="提示词版本")
|
|
rag_context_version: Mapped[str] = mapped_column(String(50), nullable=False, default="none", comment="RAG上下文版本")
|
|
case_id: Mapped[int] = mapped_column(BigInteger, nullable=False, index=True, comment="病例ID")
|
|
teacher_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, comment="教师ID")
|
|
user_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, comment="Django用户中心数字ID")
|
|
external_user_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True, comment="Django用户中心ID")
|
|
session_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, comment="训练会话ID")
|
|
evaluation_record_id: Mapped[int | None] = mapped_column(BigInteger, nullable=True, index=True, comment="兼容旧评价记录ID")
|
|
score_type: Mapped[str] = mapped_column(String(20), nullable=False, default="percentage", comment="分数类型")
|
|
pdf_file_path: Mapped[str | None] = mapped_column(String(512), comment="PDF报告路径")
|
|
|
|
__table_args__ = (
|
|
UniqueConstraint("session_id", name="uk_training_record_session"),
|
|
{"comment": "训练记录表"},
|
|
)
|
|
|
|
score_details = relationship("TrainingScoreDetail", back_populates="record", cascade="all, delete-orphan")
|
|
|
|
|
|
class TrainingScoreDetail(TimestampMixin, Base):
|
|
"""评分明细表:保存每条 scoring_rule 对应的 AI 评分、扣分原因、证据和置信度。"""
|
|
|
|
__tablename__ = "training_score_detail"
|
|
|
|
id: Mapped[int] = mapped_column(BIGINT_PK, primary_key=True, autoincrement=True, comment="评分明细ID")
|
|
record_id: Mapped[int] = mapped_column(ForeignKey("training_record.id"), nullable=False, index=True, comment="训练记录ID")
|
|
rule_id: Mapped[int | None] = mapped_column(ForeignKey("scoring_rule.id"), nullable=True, index=True, comment="评分规则ID")
|
|
dimension: Mapped[str] = mapped_column(String(50), nullable=False, index=True, comment="评分维度")
|
|
score: Mapped[Decimal] = mapped_column(Numeric(5, 2), nullable=False, default=0, comment="分数")
|
|
deducted_reason: Mapped[str | None] = mapped_column(Text, comment="扣分原因")
|
|
evidence_message_ids: Mapped[list] = mapped_column(JSON, nullable=False, default=list, comment="对应对话证据")
|
|
ai_confidence: Mapped[Decimal | None] = mapped_column(Numeric(5, 2), comment="AI评分置信度")
|
|
comment: Mapped[str | None] = mapped_column(Text, comment="评语")
|
|
|
|
record = relationship("TrainingRecord", back_populates="score_details")
|
|
|
|
__table_args__ = {"comment": "评分明细表"}
|