Spaces:
Running
Running
| """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"<CustomQA id={self.id} q={self.question[:30]}>" | |