"""Author RAG Chatbot SaaS — Custom Q&A Model. Allows authors to define custom question-answer pairs that override the RAG pipeline retrieval for specific queries. """ from sqlalchemy import Boolean, Float, ForeignKey, Integer, String, Text from sqlalchemy.orm import Mapped, mapped_column, relationship from app.models.base import Base, TimestampMixin, generate_uuid class CustomQA(Base, TimestampMixin): """Custom Q&A pair — checked before RAG pipeline.""" __tablename__ = "custom_qa" id: Mapped[str] = mapped_column(String(36), primary_key=True, default=generate_uuid) author_id: Mapped[str] = mapped_column( String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True ) book_id: Mapped[str | None] = mapped_column( String(36), ForeignKey("books.id", ondelete="SET NULL"), nullable=True, index=True ) question: Mapped[str] = mapped_column(String(500), nullable=False) answer: Mapped[str] = mapped_column(Text, nullable=False) priority: Mapped[int] = mapped_column(Integer, default=0, nullable=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) match_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False) match_threshold: Mapped[float] = mapped_column(Float, default=0.85, nullable=False) category: Mapped[str | None] = mapped_column(String(50), nullable=True) # Phase 3B: Stores JSON-serialized list[float] for semantic cosine similarity. # NULL = embedding not yet generated → Jaccard fallback used until re-saved. embedding_json: Mapped[str | None] = mapped_column(Text, nullable=True) # Relationships author: Mapped["User"] = relationship("User") book: Mapped["Book"] = relationship("Book") def __repr__(self) -> str: return f""