Arag / app /models /custom_qa.py
AuthorBot
feat: Phases 2B + 3B β€” semantic Q&A and vector store fixes
75a3a40
Raw
History Blame Contribute Delete
1.88 kB
"""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]}>"