* Delete legacy from bot * Clear old models * Единый http клиент * РАГ полечен
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
"""Remove unused embeddings table
|
||||
|
||||
Revision ID: 003
|
||||
Revises: 002
|
||||
Create Date: 2024-12-24 12:00:00.000000
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = '003'
|
||||
down_revision = '002'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.drop_table('embeddings')
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
op.create_table(
|
||||
'embeddings',
|
||||
sa.Column('embedding_id', sa.dialects.postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('document_id', sa.dialects.postgresql.UUID(as_uuid=True), nullable=False),
|
||||
sa.Column('embedding', sa.dialects.postgresql.JSON(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column('model_version', sa.String(), nullable=True),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['document_id'], ['documents.document_id'], ),
|
||||
sa.PrimaryKeyConstraint('embedding_id')
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ from src.domain.repositories.document_repository import IDocumentRepository
|
||||
from src.domain.repositories.collection_repository import ICollectionRepository
|
||||
from src.domain.repositories.collection_access_repository import ICollectionAccessRepository
|
||||
from src.application.services.document_parser_service import DocumentParserService
|
||||
from src.application.services.rag_service import RAGService
|
||||
from src.shared.exceptions import NotFoundError, ForbiddenError
|
||||
|
||||
|
||||
@@ -19,12 +20,14 @@ class DocumentUseCases:
|
||||
document_repository: IDocumentRepository,
|
||||
collection_repository: ICollectionRepository,
|
||||
access_repository: ICollectionAccessRepository,
|
||||
parser_service: DocumentParserService
|
||||
parser_service: DocumentParserService,
|
||||
rag_service: Optional[RAGService] = None
|
||||
):
|
||||
self.document_repository = document_repository
|
||||
self.collection_repository = collection_repository
|
||||
self.access_repository = access_repository
|
||||
self.parser_service = parser_service
|
||||
self.rag_service = rag_service
|
||||
|
||||
async def _check_collection_access(self, user_id: UUID, collection) -> bool:
|
||||
"""Проверить доступ пользователя к коллекции"""
|
||||
@@ -64,7 +67,7 @@ class DocumentUseCases:
|
||||
filename: str,
|
||||
user_id: UUID
|
||||
) -> Document:
|
||||
"""Загрузить и распарсить документ"""
|
||||
"""Загрузить и распарсить документ, затем автоматически проиндексировать"""
|
||||
collection = await self.collection_repository.get_by_id(collection_id)
|
||||
if not collection:
|
||||
raise NotFoundError(f"Коллекция {collection_id} не найдена")
|
||||
@@ -81,7 +84,15 @@ class DocumentUseCases:
|
||||
content=content,
|
||||
metadata={"filename": filename}
|
||||
)
|
||||
return await self.document_repository.create(document)
|
||||
document = await self.document_repository.create(document)
|
||||
|
||||
if self.rag_service:
|
||||
try:
|
||||
await self.rag_service.index_document(document)
|
||||
except Exception as e:
|
||||
print(f"Ошибка при автоматической индексации документа {document.document_id}: {e}")
|
||||
|
||||
return document
|
||||
|
||||
async def get_document(self, document_id: UUID) -> Document:
|
||||
"""Получить документ по ID"""
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
"""
|
||||
Доменная сущность 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()
|
||||
|
||||
@@ -53,19 +53,6 @@ class DocumentModel(Base):
|
||||
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):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
API для RAG: индексация документов и ответы на вопросы
|
||||
API для RAG: ответы на вопросы
|
||||
"""
|
||||
from fastapi import APIRouter, status, Request
|
||||
from typing import Annotated
|
||||
@@ -9,30 +9,13 @@ from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.rag_schemas import (
|
||||
QuestionRequest,
|
||||
RAGAnswer,
|
||||
IndexDocumentRequest,
|
||||
IndexDocumentResponse,
|
||||
)
|
||||
from src.application.use_cases.rag_use_cases import RAGUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
|
||||
router = APIRouter(prefix="/rag", tags=["rag"])
|
||||
|
||||
|
||||
@router.post("/index", response_model=IndexDocumentResponse, status_code=status.HTTP_200_OK)
|
||||
@inject
|
||||
async def index_document(
|
||||
body: IndexDocumentRequest,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[RAGUseCases, FromDishka()],
|
||||
):
|
||||
"""Индексирование идет через чанкирование, далее эмбеддинг и загрузка в векторную бд"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
result = await use_cases.index_document(body.document_id)
|
||||
return IndexDocumentResponse(**result)
|
||||
|
||||
|
||||
@router.post("/question", response_model=RAGAnswer, status_code=status.HTTP_200_OK)
|
||||
@inject
|
||||
async def ask_question(
|
||||
|
||||
@@ -26,10 +26,3 @@ class RAGAnswer(BaseModel):
|
||||
usage: dict[str, Any] = {}
|
||||
|
||||
|
||||
class IndexDocumentRequest(BaseModel):
|
||||
document_id: UUID
|
||||
|
||||
|
||||
class IndexDocumentResponse(BaseModel):
|
||||
chunks_indexed: int
|
||||
|
||||
|
||||
@@ -152,9 +152,10 @@ class UseCaseProvider(Provider):
|
||||
document_repo: IDocumentRepository,
|
||||
collection_repo: ICollectionRepository,
|
||||
access_repo: ICollectionAccessRepository,
|
||||
parser_service: DocumentParserService
|
||||
parser_service: DocumentParserService,
|
||||
rag_service: RAGService
|
||||
) -> DocumentUseCases:
|
||||
return DocumentUseCases(document_repo, collection_repo, access_repo, parser_service)
|
||||
return DocumentUseCases(document_repo, collection_repo, access_repo, parser_service, rag_service)
|
||||
|
||||
@provide(scope=Scope.REQUEST)
|
||||
def get_conversation_use_cases(
|
||||
|
||||
Reference in New Issue
Block a user