db created
This commit is contained in:
parent
39bcd1c16e
commit
ae252a796c
4
backend/src/domain/entities/__init__.py
Normal file
4
backend/src/domain/entities/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
"""
|
||||||
|
Domain entities
|
||||||
|
"""
|
||||||
|
|
||||||
26
backend/src/domain/entities/collection.py
Normal file
26
backend/src/domain/entities/collection.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность Collection
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
|
||||||
|
class Collection:
|
||||||
|
"""Каталог документов"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
owner_id: UUID,
|
||||||
|
description: str = "",
|
||||||
|
is_public: bool = False,
|
||||||
|
collection_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.collection_id = collection_id or uuid4()
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.owner_id = owner_id
|
||||||
|
self.is_public = is_public
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
22
backend/src/domain/entities/collection_access.py
Normal file
22
backend/src/domain/entities/collection_access.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность CollectionAccess
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionAccess:
|
||||||
|
"""Доступ пользователя к коллекции"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
user_id: UUID,
|
||||||
|
collection_id: UUID,
|
||||||
|
access_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.access_id = access_id or uuid4()
|
||||||
|
self.user_id = user_id
|
||||||
|
self.collection_id = collection_id
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
28
backend/src/domain/entities/conversation.py
Normal file
28
backend/src/domain/entities/conversation.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность Conversation
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
|
|
||||||
|
class Conversation:
|
||||||
|
"""Беседа пользователя с ИИ"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
user_id: UUID,
|
||||||
|
collection_id: UUID,
|
||||||
|
conversation_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None,
|
||||||
|
updated_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.conversation_id = conversation_id or uuid4()
|
||||||
|
self.user_id = user_id
|
||||||
|
self.collection_id = collection_id
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
self.updated_at = updated_at or datetime.utcnow()
|
||||||
|
|
||||||
|
def update_timestamp(self):
|
||||||
|
"""Обновить время последнего изменения"""
|
||||||
|
self.updated_at = datetime.utcnow()
|
||||||
|
|
||||||
27
backend/src/domain/entities/document.py
Normal file
27
backend/src/domain/entities/document.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность Document
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class Document:
|
||||||
|
"""Документ в коллекции"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
collection_id: UUID,
|
||||||
|
title: str,
|
||||||
|
content: str,
|
||||||
|
metadata: dict[str, Any] | None = None,
|
||||||
|
document_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.document_id = document_id or uuid4()
|
||||||
|
self.collection_id = collection_id
|
||||||
|
self.title = title
|
||||||
|
self.content = content
|
||||||
|
self.metadata = metadata or {}
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
25
backend/src/domain/entities/embedding.py
Normal file
25
backend/src/domain/entities/embedding.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность Embedding
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
|
||||||
|
class Embedding:
|
||||||
|
"""Эмбеддинг документа"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
document_id: UUID,
|
||||||
|
embedding: list[float] | None = None,
|
||||||
|
model_version: str = "",
|
||||||
|
embedding_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.embedding_id = embedding_id or uuid4()
|
||||||
|
self.document_id = document_id
|
||||||
|
self.embedding = embedding or []
|
||||||
|
self.model_version = model_version
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
35
backend/src/domain/entities/message.py
Normal file
35
backend/src/domain/entities/message.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность Message
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
from typing import Any
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class MessageRole(str, Enum):
|
||||||
|
"""Роли сообщений"""
|
||||||
|
USER = "user"
|
||||||
|
ASSISTANT = "assistant"
|
||||||
|
SYSTEM = "system"
|
||||||
|
|
||||||
|
|
||||||
|
class Message:
|
||||||
|
"""Сообщение в беседе"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
conversation_id: UUID,
|
||||||
|
content: str,
|
||||||
|
role: MessageRole,
|
||||||
|
sources: dict[str, Any] | None = None,
|
||||||
|
message_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.message_id = message_id or uuid4()
|
||||||
|
self.conversation_id = conversation_id
|
||||||
|
self.content = content
|
||||||
|
self.role = role
|
||||||
|
self.sources = sources or {}
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
33
backend/src/domain/entities/user.py
Normal file
33
backend/src/domain/entities/user.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
"""
|
||||||
|
Доменная сущность User
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
from uuid import UUID, uuid4
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class UserRole(str, Enum):
|
||||||
|
"""Роли пользователей"""
|
||||||
|
USER = "user"
|
||||||
|
ADMIN = "admin"
|
||||||
|
|
||||||
|
|
||||||
|
class User:
|
||||||
|
"""Пользователь системы"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
telegram_id: str,
|
||||||
|
role: UserRole = UserRole.USER,
|
||||||
|
user_id: UUID | None = None,
|
||||||
|
created_at: datetime | None = None
|
||||||
|
):
|
||||||
|
self.user_id = user_id or uuid4()
|
||||||
|
self.telegram_id = telegram_id
|
||||||
|
self.role = role
|
||||||
|
self.created_at = created_at or datetime.utcnow()
|
||||||
|
|
||||||
|
def is_admin(self) -> bool:
|
||||||
|
"""проверка, является ли пользователь администратором"""
|
||||||
|
return self.role == UserRole.ADMIN
|
||||||
|
|
||||||
4
backend/src/domain/repositories/__init__.py
Normal file
4
backend/src/domain/repositories/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
"""
|
||||||
|
Domain repositories interfaces
|
||||||
|
"""
|
||||||
|
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для CollectionAccess
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.collection_access import CollectionAccess
|
||||||
|
|
||||||
|
|
||||||
|
class ICollectionAccessRepository(ABC):
|
||||||
|
"""Интерфейс репозитория доступа к коллекциям"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, access: CollectionAccess) -> CollectionAccess:
|
||||||
|
"""Создать доступ"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, access_id: UUID) -> Optional[CollectionAccess]:
|
||||||
|
"""Получить доступ по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, access_id: UUID) -> bool:
|
||||||
|
"""Удалить доступ"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete_by_user_and_collection(self, user_id: UUID, collection_id: UUID) -> bool:
|
||||||
|
"""Удалить доступ пользователя к коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_user_and_collection(self, user_id: UUID, collection_id: UUID) -> Optional[CollectionAccess]:
|
||||||
|
"""Получить доступ пользователя к коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_user(self, user_id: UUID) -> list[CollectionAccess]:
|
||||||
|
"""Получить доступы пользователя"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_collection(self, collection_id: UUID) -> list[CollectionAccess]:
|
||||||
|
"""Получить доступы к коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
42
backend/src/domain/repositories/collection_repository.py
Normal file
42
backend/src/domain/repositories/collection_repository.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для Collection
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.collection import Collection
|
||||||
|
|
||||||
|
|
||||||
|
class ICollectionRepository(ABC):
|
||||||
|
"""Интерфейс репозитория коллекций"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, collection: Collection) -> Collection:
|
||||||
|
"""Создать коллекцию"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, collection_id: UUID) -> Optional[Collection]:
|
||||||
|
"""Получить коллекцию по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update(self, collection: Collection) -> Collection:
|
||||||
|
"""Обновить коллекцию"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, collection_id: UUID) -> bool:
|
||||||
|
"""Удалить коллекцию"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_owner(self, owner_id: UUID, skip: int = 0, limit: int = 100) -> list[Collection]:
|
||||||
|
"""Получить коллекции владельца"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_public(self, skip: int = 0, limit: int = 100) -> list[Collection]:
|
||||||
|
"""Получить публичные коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
42
backend/src/domain/repositories/conversation_repository.py
Normal file
42
backend/src/domain/repositories/conversation_repository.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для Conversation
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.conversation import Conversation
|
||||||
|
|
||||||
|
|
||||||
|
class IConversationRepository(ABC):
|
||||||
|
"""Интерфейс репозитория бесед"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, conversation: Conversation) -> Conversation:
|
||||||
|
"""Создать беседу"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, conversation_id: UUID) -> Optional[Conversation]:
|
||||||
|
"""Получить беседу по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update(self, conversation: Conversation) -> Conversation:
|
||||||
|
"""Обновить беседу"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, conversation_id: UUID) -> bool:
|
||||||
|
"""Удалить беседу"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_user(self, user_id: UUID, skip: int = 0, limit: int = 100) -> list[Conversation]:
|
||||||
|
"""Получить беседы пользователя"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_collection(self, collection_id: UUID, skip: int = 0, limit: int = 100) -> list[Conversation]:
|
||||||
|
"""Получить беседы по коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
37
backend/src/domain/repositories/document_repository.py
Normal file
37
backend/src/domain/repositories/document_repository.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для Document
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.document import Document
|
||||||
|
|
||||||
|
|
||||||
|
class IDocumentRepository(ABC):
|
||||||
|
"""Интерфейс репозитория документов"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, document: Document) -> Document:
|
||||||
|
"""Создать документ"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, document_id: UUID) -> Optional[Document]:
|
||||||
|
"""Получить документ по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update(self, document: Document) -> Document:
|
||||||
|
"""Обновить документ"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, document_id: UUID) -> bool:
|
||||||
|
"""Удалить документ"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_collection(self, collection_id: UUID, skip: int = 0, limit: int = 100) -> list[Document]:
|
||||||
|
"""Получить документы коллекции"""
|
||||||
|
pass
|
||||||
|
|
||||||
37
backend/src/domain/repositories/message_repository.py
Normal file
37
backend/src/domain/repositories/message_repository.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для Message
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.message import Message
|
||||||
|
|
||||||
|
|
||||||
|
class IMessageRepository(ABC):
|
||||||
|
"""Интерфейс репозитория сообщений"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, message: Message) -> Message:
|
||||||
|
"""Создать сообщение"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, message_id: UUID) -> Optional[Message]:
|
||||||
|
"""Получить сообщение по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update(self, message: Message) -> Message:
|
||||||
|
"""Обновить сообщение"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, message_id: UUID) -> bool:
|
||||||
|
"""Удалить сообщение"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_by_conversation(self, conversation_id: UUID, skip: int = 0, limit: int = 100) -> list[Message]:
|
||||||
|
"""Получить сообщения беседы"""
|
||||||
|
pass
|
||||||
|
|
||||||
42
backend/src/domain/repositories/user_repository.py
Normal file
42
backend/src/domain/repositories/user_repository.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
"""
|
||||||
|
Интерфейс репозитория для User
|
||||||
|
"""
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from uuid import UUID
|
||||||
|
from typing import Optional
|
||||||
|
from src.domain.entities.user import User
|
||||||
|
|
||||||
|
|
||||||
|
class IUserRepository(ABC):
|
||||||
|
"""Интерфейс репозитория пользователей"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def create(self, user: User) -> User:
|
||||||
|
"""Создать пользователя"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_id(self, user_id: UUID) -> Optional[User]:
|
||||||
|
"""Получить пользователя по ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def get_by_telegram_id(self, telegram_id: str) -> Optional[User]:
|
||||||
|
"""Получить пользователя по Telegram ID"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def update(self, user: User) -> User:
|
||||||
|
"""Обновить пользователя"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def delete(self, user_id: UUID) -> bool:
|
||||||
|
"""Удалить пользователя"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def list_all(self, skip: int = 0, limit: int = 100) -> list[User]:
|
||||||
|
"""Получить список всех пользователей"""
|
||||||
|
pass
|
||||||
|
|
||||||
4
backend/src/infrastructure/database/__init__.py
Normal file
4
backend/src/infrastructure/database/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
"""
|
||||||
|
Database infrastructure
|
||||||
|
"""
|
||||||
|
|
||||||
32
backend/src/infrastructure/database/base.py
Normal file
32
backend/src/infrastructure/database/base.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
"""
|
||||||
|
Базовые настройки базы данных
|
||||||
|
"""
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
|
||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
|
from src.shared.config import settings
|
||||||
|
|
||||||
|
engine = create_async_engine(
|
||||||
|
settings.database_url.replace("postgresql://", "postgresql+asyncpg://"),
|
||||||
|
echo=settings.DEBUG,
|
||||||
|
future=True
|
||||||
|
)
|
||||||
|
|
||||||
|
AsyncSessionLocal = async_sessionmaker(
|
||||||
|
engine,
|
||||||
|
class_=AsyncSession,
|
||||||
|
expire_on_commit=False,
|
||||||
|
autocommit=False,
|
||||||
|
autoflush=False
|
||||||
|
)
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
|
async def get_db() -> AsyncSession:
|
||||||
|
"""Dependency для получения сессии БД"""
|
||||||
|
async with AsyncSessionLocal() as session:
|
||||||
|
try:
|
||||||
|
yield session
|
||||||
|
finally:
|
||||||
|
await session.close()
|
||||||
|
|
||||||
109
backend/src/infrastructure/database/models.py
Normal file
109
backend/src/infrastructure/database/models.py
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
"""
|
||||||
|
SQLAlchemy модели для базы данных
|
||||||
|
"""
|
||||||
|
from sqlalchemy import Column, String, Text, Boolean, DateTime, ForeignKey, JSON, Integer
|
||||||
|
from sqlalchemy.dialects.postgresql import UUID
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from datetime import datetime
|
||||||
|
import uuid
|
||||||
|
from src.infrastructure.database.base import Base
|
||||||
|
|
||||||
|
|
||||||
|
class UserModel(Base):
|
||||||
|
"""Модель пользователя"""
|
||||||
|
__tablename__ = "users"
|
||||||
|
|
||||||
|
user_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
telegram_id = Column(String, unique=True, nullable=False, index=True)
|
||||||
|
role = Column(String, nullable=False, default="user")
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
collections = relationship("CollectionModel", back_populates="owner", cascade="all, delete-orphan")
|
||||||
|
conversations = relationship("ConversationModel", back_populates="user", cascade="all, delete-orphan")
|
||||||
|
collection_accesses = relationship("CollectionAccessModel", back_populates="user", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionModel(Base):
|
||||||
|
"""Модель коллекции"""
|
||||||
|
__tablename__ = "collections"
|
||||||
|
|
||||||
|
collection_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
name = Column(String, nullable=False)
|
||||||
|
description = Column(Text, nullable=True)
|
||||||
|
owner_id = Column(UUID(as_uuid=True), ForeignKey("users.user_id"), nullable=False)
|
||||||
|
is_public = Column(Boolean, nullable=False, default=False)
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
owner = relationship("UserModel", back_populates="collections")
|
||||||
|
documents = relationship("DocumentModel", back_populates="collection", cascade="all, delete-orphan")
|
||||||
|
conversations = relationship("ConversationModel", back_populates="collection", cascade="all, delete-orphan")
|
||||||
|
accesses = relationship("CollectionAccessModel", back_populates="collection", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentModel(Base):
|
||||||
|
"""Модель документа"""
|
||||||
|
__tablename__ = "documents"
|
||||||
|
|
||||||
|
document_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
collection_id = Column(UUID(as_uuid=True), ForeignKey("collections.collection_id"), nullable=False)
|
||||||
|
title = Column(String, nullable=False)
|
||||||
|
content = Column(Text, nullable=False)
|
||||||
|
document_metadata = Column("metadata", JSON, nullable=True, default={})
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
collection = relationship("CollectionModel", back_populates="documents")
|
||||||
|
embeddings = relationship("EmbeddingModel", back_populates="document", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddingModel(Base):
|
||||||
|
"""Модель эмбеддинга (заглушка)"""
|
||||||
|
__tablename__ = "embeddings"
|
||||||
|
|
||||||
|
embedding_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
document_id = Column(UUID(as_uuid=True), ForeignKey("documents.document_id"), nullable=False)
|
||||||
|
embedding = Column(JSON, nullable=True)
|
||||||
|
model_version = Column(String, nullable=True)
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
document = relationship("DocumentModel", back_populates="embeddings")
|
||||||
|
|
||||||
|
|
||||||
|
class ConversationModel(Base):
|
||||||
|
"""Модель беседы"""
|
||||||
|
__tablename__ = "conversations"
|
||||||
|
|
||||||
|
conversation_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
user_id = Column(UUID(as_uuid=True), ForeignKey("users.user_id"), nullable=False)
|
||||||
|
collection_id = Column(UUID(as_uuid=True), ForeignKey("collections.collection_id"), nullable=False)
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||||
|
|
||||||
|
user = relationship("UserModel", back_populates="conversations")
|
||||||
|
collection = relationship("CollectionModel", back_populates="conversations")
|
||||||
|
messages = relationship("MessageModel", back_populates="conversation", cascade="all, delete-orphan")
|
||||||
|
|
||||||
|
|
||||||
|
class MessageModel(Base):
|
||||||
|
"""Модель сообщения"""
|
||||||
|
__tablename__ = "messages"
|
||||||
|
|
||||||
|
message_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
conversation_id = Column(UUID(as_uuid=True), ForeignKey("conversations.conversation_id"), nullable=False)
|
||||||
|
content = Column(Text, nullable=False)
|
||||||
|
role = Column(String, nullable=False)
|
||||||
|
sources = Column(JSON, nullable=True, default={})
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
conversation = relationship("ConversationModel", back_populates="messages")
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionAccessModel(Base):
|
||||||
|
"""Модель доступа к коллекции"""
|
||||||
|
__tablename__ = "collection_access"
|
||||||
|
|
||||||
|
access_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
||||||
|
user_id = Column(UUID(as_uuid=True), ForeignKey("users.user_id"), nullable=False)
|
||||||
|
collection_id = Column(UUID(as_uuid=True), ForeignKey("collections.collection_id"), nullable=False)
|
||||||
|
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
||||||
|
user = relationship("UserModel", back_populates="collection_accesses")
|
||||||
|
collection = relationship("CollectionModel", back_populates="accesses")
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
{"comment": "Уникальный доступ пользователя к коллекции"},
|
||||||
|
)
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user