from __future__ import annotations from sqlalchemy import ( BIGINT, BOOLEAN, TIMESTAMP, Column, Date, DateTime, ForeignKey, Index, Integer, String, Text, VARCHAR, ) from sqlalchemy.dialects.postgresql import JSONB, TSVECTOR from sqlalchemy.orm import declarative_base, relationship BaseModel = declarative_base() class User(BaseModel): __tablename__ = "users" user_id = Column(BIGINT, primary_key=True) username = Column(VARCHAR(33), nullable=True) fullname = Column(VARCHAR(128), nullable=False) country = Column(Text, nullable=False, default="Россия") region = Column(Text, nullable=True) user_type = Column(Text, nullable=False, default="physical_person") register_date = Column(DateTime(timezone=True), nullable=False) updated_at = Column(DateTime(timezone=True), nullable=False) class Admin(BaseModel): __tablename__ = "admins" user_id = Column(BIGINT, primary_key=True) username = Column(VARCHAR(33), nullable=True) fullname = Column(VARCHAR(128), nullable=False) class Blacklist(BaseModel): __tablename__ = "blacklist" user_id = Column(BIGINT, primary_key=True) class Setting(BaseModel): __tablename__ = "settings" name = Column(String, primary_key=True) value = Column(JSONB, nullable=True) class Consultation(BaseModel): __tablename__ = "consultations" id = Column(BIGINT, primary_key=True, autoincrement=True) user_id = Column(BIGINT, ForeignKey("users.user_id", ondelete="CASCADE"), nullable=False) category = Column(Text, nullable=False) title = Column(Text, nullable=True) region = Column(Text, nullable=True) status = Column(Text, nullable=False, default="active") created_at = Column(TIMESTAMP(timezone=True), nullable=False) updated_at = Column(TIMESTAMP(timezone=True), nullable=False) messages = relationship("Message", back_populates="consultation") rag_queries = relationship("RagQuery", back_populates="consultation") class Message(BaseModel): __tablename__ = "messages" id = Column(BIGINT, primary_key=True, autoincrement=True) consultation_id = Column( BIGINT, ForeignKey("consultations.id", ondelete="CASCADE"), nullable=False, ) role = Column(Text, nullable=False) content = Column(Text, nullable=False) sources_json = Column(JSONB, nullable=True) created_at = Column(TIMESTAMP(timezone=True), nullable=False) consultation = relationship("Consultation", back_populates="messages") rag_queries = relationship("RagQuery", back_populates="user_message") class LawSource(BaseModel): __tablename__ = "law_sources" id = Column(BIGINT, primary_key=True, autoincrement=True) title = Column(Text, nullable=False) source_type = Column(Text, nullable=False) jurisdiction = Column(Text, nullable=False, default="RU") law_type = Column(Text, nullable=True) document_number = Column(Text, nullable=True) adoption_date = Column(Date, nullable=True) publication_date = Column(Date, nullable=True) effective_date = Column(Date, nullable=True) source_url = Column(Text, nullable=False) official_publication_number = Column(Text, nullable=True) version_hash = Column(Text, nullable=False) is_active = Column(BOOLEAN, nullable=False, default=True) loaded_at = Column(TIMESTAMP(timezone=True), nullable=False) chunks = relationship("LawChunk", back_populates="source") __table_args__ = ( Index("law_sources_source_url_idx", "source_url"), Index("law_sources_active_url_idx", "source_url", "is_active"), ) class LawChunk(BaseModel): __tablename__ = "law_chunks" id = Column(BIGINT, primary_key=True, autoincrement=True) source_id = Column( BIGINT, ForeignKey("law_sources.id", ondelete="CASCADE"), nullable=False, ) chunk_index = Column(Integer, nullable=False) article_number = Column(Text, nullable=True) article_title = Column(Text, nullable=True) chunk_text = Column(Text, nullable=False) chunk_metadata = Column("metadata", JSONB, nullable=False) tsv = Column(TSVECTOR, nullable=True) created_at = Column(TIMESTAMP(timezone=True), nullable=False) source = relationship("LawSource", back_populates="chunks") __table_args__ = ( Index("law_chunks_source_id_idx", "source_id"), Index("law_chunks_article_number_idx", "article_number"), Index("law_chunks_tsv_idx", "tsv", postgresql_using="gin"), ) class RagQuery(BaseModel): __tablename__ = "rag_queries" id = Column(BIGINT, primary_key=True, autoincrement=True) consultation_id = Column( BIGINT, ForeignKey("consultations.id", ondelete="CASCADE"), nullable=True, ) user_message_id = Column( BIGINT, ForeignKey("messages.id", ondelete="CASCADE"), nullable=True, ) generated_queries = Column(JSONB, nullable=False) retrieved_chunks = Column(JSONB, nullable=False) created_at = Column(TIMESTAMP(timezone=True), nullable=False) consultation = relationship("Consultation", back_populates="rag_queries") user_message = relationship("Message", back_populates="rag_queries")