"""ORM model definitions""" from datetime import datetime from typing import Optional, List from sqlalchemy import String, Integer, Boolean, Float, Text, DateTime, ForeignKey from sqlalchemy.orm import Mapped, mapped_column, relationship, DeclarativeBase class Base(DeclarativeBase): pass class Project(Base): """Project model""" __tablename__ = "projects" id: Mapped[str] = mapped_column(String(64), primary_key=True) user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) name: Mapped[str] = mapped_column(String(255), nullable=False) description: Mapped[Optional[str]] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships user: Mapped["User"] = relationship("User", backref="projects") class User(Base): """User model""" __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True) username: Mapped[str] = mapped_column(String(50), unique=True, nullable=False) email: Mapped[Optional[str]] = mapped_column(String(120), unique=True, nullable=True) password_hash: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) role: Mapped[str] = mapped_column(String(20), default="user") is_active: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) # Relationships conversations: Mapped[List["Conversation"]] = relationship( "Conversation", back_populates="user", cascade="all, delete-orphan" ) def to_dict(self): return { "id": self.id, "username": self.username, "email": self.email, "role": self.role, "is_active": self.is_active, "created_at": self.created_at.isoformat() if self.created_at else None } class Conversation(Base): """Conversation model""" __tablename__ = "conversations" id: Mapped[str] = mapped_column(String(64), primary_key=True) user_id: Mapped[int] = mapped_column(Integer, ForeignKey("users.id"), nullable=False) project_id: Mapped[Optional[str]] = mapped_column(String(64), ForeignKey("projects.id"), nullable=True) title: Mapped[str] = mapped_column(String(255), nullable=False) model: Mapped[str] = mapped_column(String(64), nullable=False, default="deepseek-chat") system_prompt: Mapped[str] = mapped_column(Text, nullable=False, default="You are a helpful assistant.") temperature: Mapped[float] = mapped_column(Float, default=0.7) max_tokens: Mapped[int] = mapped_column(Integer, default=2000) thinking_enabled: Mapped[bool] = mapped_column(Boolean, default=False) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships user: Mapped["User"] = relationship("User", back_populates="conversations") messages: Mapped[List["Message"]] = relationship( "Message", back_populates="conversation", cascade="all, delete-orphan" ) def to_dict(self): return { "id": self.id, "user_id": self.user_id, "project_id": self.project_id, "title": self.title, "model": self.model, "system_prompt": self.system_prompt, "temperature": self.temperature, "max_tokens": self.max_tokens, "thinking_enabled": self.thinking_enabled, "created_at": self.created_at.isoformat() if self.created_at else None, "updated_at": self.updated_at.isoformat() if self.updated_at else None } class Message(Base): """Message model""" __tablename__ = "messages" id: Mapped[str] = mapped_column(String(64), primary_key=True) conversation_id: Mapped[str] = mapped_column(String(64), ForeignKey("conversations.id"), nullable=False) role: Mapped[str] = mapped_column(String(16), nullable=False) content: Mapped[str] = mapped_column(Text, nullable=False) token_count: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) # Relationships conversation: Mapped["Conversation"] = relationship("Conversation", back_populates="messages") def to_dict(self): return { "id": self.id, "conversation_id": self.conversation_id, "role": self.role, "content": self.content, "token_count": self.token_count, "created_at": self.created_at.isoformat() if self.created_at else None }