| """Copy Check models — answer-sheet evaluation & plagiarism detection."""
|
|
|
| import uuid
|
| from datetime import datetime, timezone
|
| from sqlalchemy import String, Integer, Float, Text, DateTime, ForeignKey, JSON
|
| from sqlalchemy.orm import Mapped, mapped_column
|
| from mac.database import Base
|
|
|
|
|
| def _utcnow():
|
| return datetime.now(timezone.utc)
|
|
|
|
|
| def _gen_uuid():
|
| return str(uuid.uuid4())
|
|
|
|
|
| class CopyCheckSession(Base):
|
| """One exam evaluation round (e.g. 'DSA Mid-Term, CSE, Nov 2025')."""
|
| __tablename__ = "copy_check_sessions"
|
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_gen_uuid)
|
| created_by: Mapped[str] = mapped_column(String(36), ForeignKey("users.id"), nullable=False, index=True)
|
| subject: Mapped[str] = mapped_column(String(200), nullable=False)
|
| class_name: Mapped[str] = mapped_column(String(100), nullable=False, default="")
|
| department: Mapped[str] = mapped_column(String(50), nullable=False, default="CSE")
|
| total_marks: Mapped[int] = mapped_column(Integer, nullable=False, default=100)
|
|
|
| syllabus_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| syllabus_file_path: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
| status: Mapped[str] = mapped_column(String(20), nullable=False, default="active")
|
|
|
| sheet_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
| evaluated_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
| plagiarism_run: Mapped[bool] = mapped_column(String(1), nullable=False, default="0")
|
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow)
|
| updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow, onupdate=_utcnow)
|
|
|
|
|
| class CopyCheckSheet(Base):
|
| """One student's answer sheet within a session."""
|
| __tablename__ = "copy_check_sheets"
|
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_gen_uuid)
|
| session_id: Mapped[str] = mapped_column(String(36), ForeignKey("copy_check_sessions.id", ondelete="CASCADE"), nullable=False, index=True)
|
| student_roll: Mapped[str] = mapped_column(String(50), nullable=False)
|
| student_name: Mapped[str] = mapped_column(String(200), nullable=False, default="")
|
| department: Mapped[str] = mapped_column(String(50), nullable=False, default="")
|
| file_path: Mapped[str] = mapped_column(String(500), nullable=False)
|
| file_name: Mapped[str] = mapped_column(String(200), nullable=False, default="")
|
|
|
| ai_marks: Mapped[float | None] = mapped_column(Float, nullable=True)
|
| ai_feedback: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| extracted_text: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| status: Mapped[str] = mapped_column(String(20), nullable=False, default="uploaded")
|
|
|
| error_message: Mapped[str | None] = mapped_column(String(500), nullable=True)
|
| evaluated_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
| uploaded_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow)
|
|
|
|
|
| class CopyCheckPlagiarism(Base):
|
| """Pairwise plagiarism result between two students in a session."""
|
| __tablename__ = "copy_check_plagiarism"
|
|
|
| id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_gen_uuid)
|
| session_id: Mapped[str] = mapped_column(String(36), ForeignKey("copy_check_sessions.id", ondelete="CASCADE"), nullable=False, index=True)
|
| roll_a: Mapped[str] = mapped_column(String(50), nullable=False)
|
| roll_b: Mapped[str] = mapped_column(String(50), nullable=False)
|
| similarity_score: Mapped[float] = mapped_column(Float, nullable=False)
|
| matched_sections: Mapped[str | None] = mapped_column(Text, nullable=True)
|
| verdict: Mapped[str] = mapped_column(String(20), nullable=False, default="unlikely")
|
|
|
| created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=_utcnow)
|
|
|