fixed DI
This commit is contained in:
parent
493c385cb1
commit
dfc188e179
@ -9,7 +9,7 @@ python-multipart==0.0.6
|
||||
httpx==0.25.2
|
||||
PyMuPDF==1.23.8
|
||||
Pillow==10.2.0
|
||||
dishka==1.7.2
|
||||
dishka==0.7.0
|
||||
numpy==1.26.4
|
||||
sentence-transformers==2.7.0
|
||||
qdrant-client==1.9.0
|
||||
|
||||
@ -26,7 +26,7 @@ class CacheService:
|
||||
"question": question,
|
||||
"answer": answer
|
||||
}
|
||||
await self.reids_client.set_json(key, value, ttl or self.default_ttl)
|
||||
await self.redis_client.set_json(key, value, ttl or self.default_ttl)
|
||||
|
||||
async def invalidate_collection_cache(self, collection_id: UUID):
|
||||
pattern = f"rag:answer:{collection_id}:*"
|
||||
|
||||
@ -1,58 +1,64 @@
|
||||
"""
|
||||
Админ-панель - упрощенная версия через API эндпоинты
|
||||
В будущем можно интегрировать полноценную админ-панель
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from typing import List
|
||||
from uuid import UUID
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from src.presentation.schemas.user_schemas import UserResponse
|
||||
from src.presentation.schemas.collection_schemas import CollectionResponse
|
||||
from src.presentation.schemas.document_schemas import DocumentResponse
|
||||
from src.presentation.schemas.conversation_schemas import ConversationResponse
|
||||
from src.presentation.schemas.message_schemas import MessageResponse
|
||||
from src.domain.entities.user import User, UserRole
|
||||
from src.application.use_cases.user_use_cases import UserUseCases
|
||||
from src.application.use_cases.collection_use_cases import CollectionUseCases
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
|
||||
@router.get("/users", response_model=List[UserResponse])
|
||||
async def admin_list_users(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
):
|
||||
"""Получить список всех пользователей (только для админов)"""
|
||||
if not current_user.is_admin():
|
||||
raise HTTPException(status_code=403, detail="Требуются права администратора")
|
||||
users = await use_cases.list_users(skip=skip, limit=limit)
|
||||
return [UserResponse.from_entity(user) for user in users]
|
||||
|
||||
|
||||
@router.get("/collections", response_model=List[CollectionResponse])
|
||||
async def admin_list_collections(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Получить список всех коллекций (только для админов)"""
|
||||
from src.infrastructure.database.base import AsyncSessionLocal
|
||||
from src.infrastructure.repositories.postgresql.collection_repository import PostgreSQLCollectionRepository
|
||||
from sqlalchemy import select
|
||||
from src.infrastructure.database.models import CollectionModel
|
||||
|
||||
async with AsyncSessionLocal() as session:
|
||||
repo = PostgreSQLCollectionRepository(session)
|
||||
result = await session.execute(
|
||||
select(CollectionModel).offset(skip).limit(limit)
|
||||
)
|
||||
db_collections = result.scalars().all()
|
||||
collections = [repo._to_entity(c) for c in db_collections if c]
|
||||
return [CollectionResponse.from_entity(c) for c in collections if c]
|
||||
|
||||
"""
|
||||
Админ-панель - упрощенная версия через API эндпоинты
|
||||
В будущем можно интегрировать полноценную админ-панель
|
||||
"""
|
||||
from fastapi import APIRouter, HTTPException, Request
|
||||
from typing import List, Annotated
|
||||
from uuid import UUID
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.user_schemas import UserResponse
|
||||
from src.presentation.schemas.collection_schemas import CollectionResponse
|
||||
from src.presentation.schemas.document_schemas import DocumentResponse
|
||||
from src.presentation.schemas.conversation_schemas import ConversationResponse
|
||||
from src.presentation.schemas.message_schemas import MessageResponse
|
||||
from src.domain.entities.user import User, UserRole
|
||||
from src.application.use_cases.user_use_cases import UserUseCases
|
||||
from src.application.use_cases.collection_use_cases import CollectionUseCases
|
||||
|
||||
router = APIRouter(prefix="/admin", tags=["admin"])
|
||||
|
||||
|
||||
@router.get("/users", response_model=List[UserResponse])
|
||||
@inject
|
||||
async def admin_list_users(
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить список всех пользователей (только для админов)"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
if not current_user.is_admin():
|
||||
raise HTTPException(status_code=403, detail="Требуются права администратора")
|
||||
users = await use_cases.list_users(skip=skip, limit=limit)
|
||||
return [UserResponse.from_entity(user) for user in users]
|
||||
|
||||
|
||||
@router.get("/collections", response_model=List[CollectionResponse])
|
||||
@inject
|
||||
async def admin_list_collections(
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить список всех коллекций (только для админов)"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
from src.infrastructure.database.base import AsyncSessionLocal
|
||||
from src.infrastructure.repositories.postgresql.collection_repository import PostgreSQLCollectionRepository
|
||||
from sqlalchemy import select
|
||||
from src.infrastructure.database.models import CollectionModel
|
||||
|
||||
async with AsyncSessionLocal() as session:
|
||||
repo = PostgreSQLCollectionRepository(session)
|
||||
result = await session.execute(
|
||||
select(CollectionModel).offset(skip).limit(limit)
|
||||
)
|
||||
db_collections = result.scalars().all()
|
||||
collections = [repo._to_entity(c) for c in db_collections if c]
|
||||
return [CollectionResponse.from_entity(c) for c in collections if c]
|
||||
|
||||
|
||||
@ -1,121 +1,140 @@
|
||||
"""
|
||||
API роутеры для работы с коллекциями
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from src.presentation.schemas.collection_schemas import (
|
||||
CollectionCreate,
|
||||
CollectionUpdate,
|
||||
CollectionResponse,
|
||||
CollectionAccessGrant,
|
||||
CollectionAccessResponse
|
||||
)
|
||||
from src.application.use_cases.collection_use_cases import CollectionUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/collections", tags=["collections"])
|
||||
|
||||
|
||||
@router.post("", response_model=CollectionResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_collection(
|
||||
collection_data: CollectionCreate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Создать коллекцию"""
|
||||
collection = await use_cases.create_collection(
|
||||
name=collection_data.name,
|
||||
owner_id=current_user.user_id,
|
||||
description=collection_data.description,
|
||||
is_public=collection_data.is_public
|
||||
)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.get("/{collection_id}", response_model=CollectionResponse)
|
||||
async def get_collection(
|
||||
collection_id: UUID,
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Получить коллекцию по ID"""
|
||||
collection = await use_cases.get_collection(collection_id)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.put("/{collection_id}", response_model=CollectionResponse)
|
||||
async def update_collection(
|
||||
collection_id: UUID,
|
||||
collection_data: CollectionUpdate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Обновить коллекцию"""
|
||||
collection = await use_cases.update_collection(
|
||||
collection_id=collection_id,
|
||||
user_id=current_user.user_id,
|
||||
name=collection_data.name,
|
||||
description=collection_data.description,
|
||||
is_public=collection_data.is_public
|
||||
)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.delete("/{collection_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_collection(
|
||||
collection_id: UUID,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Удалить коллекцию"""
|
||||
await use_cases.delete_collection(collection_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("", response_model=List[CollectionResponse])
|
||||
async def list_collections(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Получить список коллекций, доступных пользователю"""
|
||||
collections = await use_cases.list_user_collections(
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [CollectionResponse.from_entity(c) for c in collections]
|
||||
|
||||
|
||||
@router.post("/{collection_id}/access", response_model=CollectionAccessResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def grant_access(
|
||||
collection_id: UUID,
|
||||
access_data: CollectionAccessGrant,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Предоставить доступ пользователю к коллекции"""
|
||||
access = await use_cases.grant_access(
|
||||
collection_id=collection_id,
|
||||
user_id=access_data.user_id,
|
||||
owner_id=current_user.user_id
|
||||
)
|
||||
return CollectionAccessResponse.from_entity(access)
|
||||
|
||||
|
||||
@router.delete("/{collection_id}/access/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def revoke_access(
|
||||
collection_id: UUID,
|
||||
user_id: UUID,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: CollectionUseCases = FromDishka()
|
||||
):
|
||||
"""Отозвать доступ пользователя к коллекции"""
|
||||
await use_cases.revoke_access(collection_id, user_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
"""
|
||||
API роутеры для работы с коллекциями
|
||||
"""
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, Depends, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List, Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.collection_schemas import (
|
||||
CollectionCreate,
|
||||
CollectionUpdate,
|
||||
CollectionResponse,
|
||||
CollectionAccessGrant,
|
||||
CollectionAccessResponse
|
||||
)
|
||||
from src.application.use_cases.collection_use_cases import CollectionUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/collections", tags=["collections"])
|
||||
|
||||
|
||||
@router.post("", response_model=CollectionResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def create_collection(
|
||||
collection_data: CollectionCreate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Создать коллекцию"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
collection = await use_cases.create_collection(
|
||||
name=collection_data.name,
|
||||
owner_id=current_user.user_id,
|
||||
description=collection_data.description,
|
||||
is_public=collection_data.is_public
|
||||
)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.get("/{collection_id}", response_model=CollectionResponse)
|
||||
@inject
|
||||
async def get_collection(
|
||||
collection_id: UUID,
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить коллекцию по ID"""
|
||||
collection = await use_cases.get_collection(collection_id)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.put("/{collection_id}", response_model=CollectionResponse)
|
||||
@inject
|
||||
async def update_collection(
|
||||
collection_id: UUID,
|
||||
collection_data: CollectionUpdate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Обновить коллекцию"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
collection = await use_cases.update_collection(
|
||||
collection_id=collection_id,
|
||||
user_id=current_user.user_id,
|
||||
name=collection_data.name,
|
||||
description=collection_data.description,
|
||||
is_public=collection_data.is_public
|
||||
)
|
||||
return CollectionResponse.from_entity(collection)
|
||||
|
||||
|
||||
@router.delete("/{collection_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
async def delete_collection(
|
||||
collection_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Удалить коллекцию"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
await use_cases.delete_collection(collection_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("", response_model=List[CollectionResponse])
|
||||
@inject
|
||||
async def list_collections(
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить список коллекций, доступных пользователю"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
collections = await use_cases.list_user_collections(
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [CollectionResponse.from_entity(c) for c in collections]
|
||||
|
||||
|
||||
@router.post("/{collection_id}/access", response_model=CollectionAccessResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def grant_access(
|
||||
collection_id: UUID,
|
||||
access_data: CollectionAccessGrant,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Предоставить доступ пользователю к коллекции"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
access = await use_cases.grant_access(
|
||||
collection_id=collection_id,
|
||||
user_id=access_data.user_id,
|
||||
owner_id=current_user.user_id
|
||||
)
|
||||
return CollectionAccessResponse.from_entity(access)
|
||||
|
||||
|
||||
@router.delete("/{collection_id}/access/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
async def revoke_access(
|
||||
collection_id: UUID,
|
||||
user_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||
):
|
||||
"""Отозвать доступ пользователя к коллекции"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
await use_cases.revoke_access(collection_id, user_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@ -1,71 +1,83 @@
|
||||
"""
|
||||
API роутеры для работы с беседами
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from src.presentation.schemas.conversation_schemas import (
|
||||
ConversationCreate,
|
||||
ConversationResponse
|
||||
)
|
||||
from src.application.use_cases.conversation_use_cases import ConversationUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/conversations", tags=["conversations"])
|
||||
|
||||
|
||||
@router.post("", response_model=ConversationResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_conversation(
|
||||
conversation_data: ConversationCreate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: ConversationUseCases = FromDishka()
|
||||
):
|
||||
"""Создать беседу"""
|
||||
conversation = await use_cases.create_conversation(
|
||||
user_id=current_user.user_id,
|
||||
collection_id=conversation_data.collection_id
|
||||
)
|
||||
return ConversationResponse.from_entity(conversation)
|
||||
|
||||
|
||||
@router.get("/{conversation_id}", response_model=ConversationResponse)
|
||||
async def get_conversation(
|
||||
conversation_id: UUID,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: ConversationUseCases = FromDishka()
|
||||
):
|
||||
"""Получить беседу по ID"""
|
||||
conversation = await use_cases.get_conversation(conversation_id, current_user.user_id)
|
||||
return ConversationResponse.from_entity(conversation)
|
||||
|
||||
|
||||
@router.delete("/{conversation_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_conversation(
|
||||
conversation_id: UUID,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: ConversationUseCases = FromDishka()
|
||||
):
|
||||
"""Удалить беседу"""
|
||||
await use_cases.delete_conversation(conversation_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("", response_model=List[ConversationResponse])
|
||||
async def list_conversations(
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: ConversationUseCases = FromDishka()
|
||||
):
|
||||
"""Получить список бесед пользователя"""
|
||||
conversations = await use_cases.list_user_conversations(
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [ConversationResponse.from_entity(c) for c in conversations]
|
||||
|
||||
"""
|
||||
API роутеры для работы с беседами
|
||||
"""
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, Depends, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List, Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.conversation_schemas import (
|
||||
ConversationCreate,
|
||||
ConversationResponse
|
||||
)
|
||||
from src.application.use_cases.conversation_use_cases import ConversationUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/conversations", tags=["conversations"])
|
||||
|
||||
|
||||
@router.post("", response_model=ConversationResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def create_conversation(
|
||||
conversation_data: ConversationCreate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[ConversationUseCases, FromDishka()]
|
||||
):
|
||||
"""Создать беседу"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
conversation = await use_cases.create_conversation(
|
||||
user_id=current_user.user_id,
|
||||
collection_id=conversation_data.collection_id
|
||||
)
|
||||
return ConversationResponse.from_entity(conversation)
|
||||
|
||||
|
||||
@router.get("/{conversation_id}", response_model=ConversationResponse)
|
||||
@inject
|
||||
async def get_conversation(
|
||||
conversation_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[ConversationUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить беседу по ID"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
conversation = await use_cases.get_conversation(conversation_id, current_user.user_id)
|
||||
return ConversationResponse.from_entity(conversation)
|
||||
|
||||
|
||||
@router.delete("/{conversation_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
async def delete_conversation(
|
||||
conversation_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[ConversationUseCases, FromDishka()]
|
||||
):
|
||||
"""Удалить беседу"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
await use_cases.delete_conversation(conversation_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("", response_model=List[ConversationResponse])
|
||||
@inject
|
||||
async def list_conversations(
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[ConversationUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить список бесед пользователя"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
conversations = await use_cases.list_user_conversations(
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [ConversationResponse.from_entity(c) for c in conversations]
|
||||
|
||||
|
||||
@ -1,123 +1,137 @@
|
||||
"""
|
||||
API роутеры для работы с документами
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, UploadFile, File
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from src.presentation.schemas.document_schemas import (
|
||||
DocumentCreate,
|
||||
DocumentUpdate,
|
||||
DocumentResponse
|
||||
)
|
||||
from src.application.use_cases.document_use_cases import DocumentUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/documents", tags=["documents"])
|
||||
|
||||
|
||||
@router.post("", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_document(
|
||||
document_data: DocumentCreate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Создать документ"""
|
||||
document = await use_cases.create_document(
|
||||
collection_id=document_data.collection_id,
|
||||
title=document_data.title,
|
||||
content=document_data.content,
|
||||
metadata=document_data.metadata
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.post("/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def upload_document(
|
||||
collection_id: UUID,
|
||||
file: UploadFile = File(...),
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Загрузить и распарсить PDF документ или изображение"""
|
||||
if not file.filename:
|
||||
raise JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"detail": "Имя файла не указано"}
|
||||
)
|
||||
|
||||
supported_formats = ['.pdf', '.png', '.jpg', '.jpeg', '.tiff', '.bmp']
|
||||
file_ext = file.filename.lower().rsplit('.', 1)[-1] if '.' in file.filename else ''
|
||||
|
||||
if f'.{file_ext}' not in supported_formats:
|
||||
raise JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"detail": f"Неподдерживаемый формат файла. Поддерживаются: {', '.join(supported_formats)}"}
|
||||
)
|
||||
|
||||
document = await use_cases.upload_and_parse_document(
|
||||
collection_id=collection_id,
|
||||
file=file.file,
|
||||
filename=file.filename,
|
||||
user_id=current_user.user_id
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.get("/{document_id}", response_model=DocumentResponse)
|
||||
async def get_document(
|
||||
document_id: UUID,
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Получить документ по ID"""
|
||||
document = await use_cases.get_document(document_id)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.put("/{document_id}", response_model=DocumentResponse)
|
||||
async def update_document(
|
||||
document_id: UUID,
|
||||
document_data: DocumentUpdate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Обновить документ"""
|
||||
document = await use_cases.update_document(
|
||||
document_id=document_id,
|
||||
user_id=current_user.user_id,
|
||||
title=document_data.title,
|
||||
content=document_data.content,
|
||||
metadata=document_data.metadata
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_document(
|
||||
document_id: UUID,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Удалить документ"""
|
||||
await use_cases.delete_document(document_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("/collection/{collection_id}", response_model=List[DocumentResponse])
|
||||
async def list_collection_documents(
|
||||
collection_id: UUID,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
use_cases: DocumentUseCases = FromDishka()
|
||||
):
|
||||
"""Получить документы коллекции"""
|
||||
documents = await use_cases.list_collection_documents(
|
||||
collection_id=collection_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [DocumentResponse.from_entity(d) for d in documents]
|
||||
|
||||
"""
|
||||
API роутеры для работы с документами
|
||||
"""
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, UploadFile, File, Depends, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List, Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.document_schemas import (
|
||||
DocumentCreate,
|
||||
DocumentUpdate,
|
||||
DocumentResponse
|
||||
)
|
||||
from src.application.use_cases.document_use_cases import DocumentUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/documents", tags=["documents"])
|
||||
|
||||
|
||||
@router.post("", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def create_document(
|
||||
document_data: DocumentCreate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()]
|
||||
):
|
||||
"""Создать документ"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
document = await use_cases.create_document(
|
||||
collection_id=document_data.collection_id,
|
||||
title=document_data.title,
|
||||
content=document_data.content,
|
||||
metadata=document_data.metadata
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.post("/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def upload_document(
|
||||
collection_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()],
|
||||
file: UploadFile = File(...)
|
||||
):
|
||||
"""Загрузить и распарсить PDF документ или изображение"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
if not file.filename:
|
||||
raise JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"detail": "Имя файла не указано"}
|
||||
)
|
||||
|
||||
supported_formats = ['.pdf', '.png', '.jpg', '.jpeg', '.tiff', '.bmp']
|
||||
file_ext = file.filename.lower().rsplit('.', 1)[-1] if '.' in file.filename else ''
|
||||
|
||||
if f'.{file_ext}' not in supported_formats:
|
||||
raise JSONResponse(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
content={"detail": f"Неподдерживаемый формат файла. Поддерживаются: {', '.join(supported_formats)}"}
|
||||
)
|
||||
|
||||
document = await use_cases.upload_and_parse_document(
|
||||
collection_id=collection_id,
|
||||
file=file.file,
|
||||
filename=file.filename,
|
||||
user_id=current_user.user_id
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.get("/{document_id}", response_model=DocumentResponse)
|
||||
@inject
|
||||
async def get_document(
|
||||
document_id: UUID,
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить документ по ID"""
|
||||
document = await use_cases.get_document(document_id)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.put("/{document_id}", response_model=DocumentResponse)
|
||||
@inject
|
||||
async def update_document(
|
||||
document_id: UUID,
|
||||
document_data: DocumentUpdate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()]
|
||||
):
|
||||
"""Обновить документ"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
document = await use_cases.update_document(
|
||||
document_id=document_id,
|
||||
user_id=current_user.user_id,
|
||||
title=document_data.title,
|
||||
content=document_data.content,
|
||||
metadata=document_data.metadata
|
||||
)
|
||||
return DocumentResponse.from_entity(document)
|
||||
|
||||
|
||||
@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
async def delete_document(
|
||||
document_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()]
|
||||
):
|
||||
"""Удалить документ"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
await use_cases.delete_document(document_id, current_user.user_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("/collection/{collection_id}", response_model=List[DocumentResponse])
|
||||
@inject
|
||||
async def list_collection_documents(
|
||||
collection_id: UUID,
|
||||
use_cases: Annotated[DocumentUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить документы коллекции"""
|
||||
documents = await use_cases.list_collection_documents(
|
||||
collection_id=collection_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [DocumentResponse.from_entity(d) for d in documents]
|
||||
|
||||
|
||||
@ -1,90 +1,99 @@
|
||||
"""
|
||||
API роутеры для работы с сообщениями
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from src.presentation.schemas.message_schemas import (
|
||||
MessageCreate,
|
||||
MessageUpdate,
|
||||
MessageResponse
|
||||
)
|
||||
from src.application.use_cases.message_use_cases import MessageUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/messages", tags=["messages"])
|
||||
|
||||
|
||||
@router.post("", response_model=MessageResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_message(
|
||||
message_data: MessageCreate,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: MessageUseCases = FromDishka()
|
||||
):
|
||||
"""Создать сообщение"""
|
||||
message = await use_cases.create_message(
|
||||
conversation_id=message_data.conversation_id,
|
||||
content=message_data.content,
|
||||
role=message_data.role,
|
||||
user_id=current_user.user_id,
|
||||
sources=message_data.sources
|
||||
)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.get("/{message_id}", response_model=MessageResponse)
|
||||
async def get_message(
|
||||
message_id: UUID,
|
||||
use_cases: MessageUseCases = FromDishka()
|
||||
):
|
||||
"""Получить сообщение по ID"""
|
||||
message = await use_cases.get_message(message_id)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.put("/{message_id}", response_model=MessageResponse)
|
||||
async def update_message(
|
||||
message_id: UUID,
|
||||
message_data: MessageUpdate,
|
||||
use_cases: MessageUseCases = FromDishka()
|
||||
):
|
||||
"""Обновить сообщение"""
|
||||
message = await use_cases.update_message(
|
||||
message_id=message_id,
|
||||
content=message_data.content,
|
||||
sources=message_data.sources
|
||||
)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.delete("/{message_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
async def delete_message(
|
||||
message_id: UUID,
|
||||
use_cases: MessageUseCases = FromDishka()
|
||||
):
|
||||
"""Удалить сообщение"""
|
||||
await use_cases.delete_message(message_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("/conversation/{conversation_id}", response_model=List[MessageResponse])
|
||||
async def list_conversation_messages(
|
||||
conversation_id: UUID,
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
current_user: User = FromDishka(),
|
||||
use_cases: MessageUseCases = FromDishka()
|
||||
):
|
||||
"""Получить сообщения беседы"""
|
||||
messages = await use_cases.list_conversation_messages(
|
||||
conversation_id=conversation_id,
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [MessageResponse.from_entity(m) for m in messages]
|
||||
|
||||
"""
|
||||
API роутеры для работы с сообщениями
|
||||
"""
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, Depends, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List, Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.message_schemas import (
|
||||
MessageCreate,
|
||||
MessageUpdate,
|
||||
MessageResponse
|
||||
)
|
||||
from src.application.use_cases.message_use_cases import MessageUseCases
|
||||
from src.domain.entities.user import User
|
||||
|
||||
router = APIRouter(prefix="/messages", tags=["messages"])
|
||||
|
||||
|
||||
@router.post("", response_model=MessageResponse, status_code=status.HTTP_201_CREATED)
|
||||
@inject
|
||||
async def create_message(
|
||||
message_data: MessageCreate,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||
):
|
||||
"""Создать сообщение"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
message = await use_cases.create_message(
|
||||
conversation_id=message_data.conversation_id,
|
||||
content=message_data.content,
|
||||
role=message_data.role,
|
||||
user_id=current_user.user_id,
|
||||
sources=message_data.sources
|
||||
)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.get("/{message_id}", response_model=MessageResponse)
|
||||
@inject
|
||||
async def get_message(
|
||||
message_id: UUID,
|
||||
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить сообщение по ID"""
|
||||
message = await use_cases.get_message(message_id)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.put("/{message_id}", response_model=MessageResponse)
|
||||
@inject
|
||||
async def update_message(
|
||||
message_id: UUID,
|
||||
message_data: MessageUpdate,
|
||||
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||
):
|
||||
"""Обновить сообщение"""
|
||||
message = await use_cases.update_message(
|
||||
message_id=message_id,
|
||||
content=message_data.content,
|
||||
sources=message_data.sources
|
||||
)
|
||||
return MessageResponse.from_entity(message)
|
||||
|
||||
|
||||
@router.delete("/{message_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
@inject
|
||||
async def delete_message(
|
||||
message_id: UUID,
|
||||
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||
):
|
||||
"""Удалить сообщение"""
|
||||
await use_cases.delete_message(message_id)
|
||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||
|
||||
|
||||
@router.get("/conversation/{conversation_id}", response_model=List[MessageResponse])
|
||||
@inject
|
||||
async def list_conversation_messages(
|
||||
conversation_id: UUID,
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[MessageUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить сообщения беседы"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
messages = await use_cases.list_conversation_messages(
|
||||
conversation_id=conversation_id,
|
||||
user_id=current_user.user_id,
|
||||
skip=skip,
|
||||
limit=limit
|
||||
)
|
||||
return [MessageResponse.from_entity(m) for m in messages]
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
"""
|
||||
API для RAG: индексация документов и ответы на вопросы
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, status
|
||||
from dishka.integrations.fastapi import FromDishka
|
||||
from fastapi import APIRouter, status, Request
|
||||
from typing import Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.rag_schemas import (
|
||||
QuestionRequest,
|
||||
RAGAnswer,
|
||||
@ -19,23 +20,29 @@ 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,
|
||||
use_cases: RAGUseCases = FromDishka(),
|
||||
current_user: User = FromDishka(),
|
||||
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(
|
||||
body: QuestionRequest,
|
||||
use_cases: RAGUseCases = FromDishka(),
|
||||
current_user: User = FromDishka(),
|
||||
request: Request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||
use_cases: Annotated[RAGUseCases, FromDishka()],
|
||||
):
|
||||
"""Отвечает на вопрос, используя RAG в рамках беседы"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
result = await use_cases.ask_question(
|
||||
conversation_id=body.conversation_id,
|
||||
user_id=current_user.user_id,
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
"""
|
||||
API роутеры для работы с пользователями
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from uuid import UUID
|
||||
from fastapi import APIRouter, status, Depends
|
||||
from fastapi import APIRouter, status, Depends, Request
|
||||
from fastapi.responses import JSONResponse
|
||||
from typing import List, Annotated
|
||||
from dishka.integrations.fastapi import FromDishka, inject
|
||||
from src.domain.repositories.user_repository import IUserRepository
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
from src.presentation.schemas.user_schemas import UserCreate, UserUpdate, UserResponse
|
||||
from src.application.use_cases.user_use_cases import UserUseCases
|
||||
from src.domain.entities.user import User
|
||||
@ -19,8 +19,8 @@ router = APIRouter(prefix="/users", tags=["users"])
|
||||
@inject
|
||||
async def create_user(
|
||||
user_data: UserCreate,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
) -> UserResponse:
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Создать пользователя"""
|
||||
user = await use_cases.create_user(
|
||||
telegram_id=user_data.telegram_id,
|
||||
@ -32,9 +32,11 @@ async def create_user(
|
||||
@router.get("/me", response_model=UserResponse)
|
||||
@inject
|
||||
async def get_current_user_info(
|
||||
current_user: User = FromDishka()
|
||||
request,
|
||||
user_repo: Annotated[IUserRepository, FromDishka()]
|
||||
):
|
||||
"""Получить информацию о текущем пользователе"""
|
||||
current_user = await get_current_user(request, user_repo)
|
||||
return UserResponse.from_entity(current_user)
|
||||
|
||||
|
||||
@ -42,7 +44,7 @@ async def get_current_user_info(
|
||||
@inject
|
||||
async def get_user_by_telegram_id(
|
||||
telegram_id: str,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить пользователя по Telegram ID"""
|
||||
user = await use_cases.get_user_by_telegram_id(telegram_id)
|
||||
@ -56,7 +58,7 @@ async def get_user_by_telegram_id(
|
||||
@inject
|
||||
async def increment_questions(
|
||||
telegram_id: str,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Увеличить счетчик использованных вопросов"""
|
||||
user = await use_cases.increment_questions_used(telegram_id)
|
||||
@ -66,9 +68,10 @@ async def increment_questions(
|
||||
@router.post("/telegram/{telegram_id}/activate-premium", response_model=UserResponse)
|
||||
@inject
|
||||
async def activate_premium(
|
||||
|
||||
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||
telegram_id: str,
|
||||
days: int = 30,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
):
|
||||
"""Активировать premium статус"""
|
||||
user = await use_cases.activate_premium(telegram_id, days=days)
|
||||
@ -79,7 +82,7 @@ async def activate_premium(
|
||||
@inject
|
||||
async def get_user(
|
||||
user_id: UUID,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Получить пользователя по ID"""
|
||||
user = await use_cases.get_user(user_id)
|
||||
@ -91,7 +94,7 @@ async def get_user(
|
||||
async def update_user(
|
||||
user_id: UUID,
|
||||
user_data: UserUpdate,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Обновить пользователя"""
|
||||
user = await use_cases.update_user(
|
||||
@ -106,7 +109,7 @@ async def update_user(
|
||||
@inject
|
||||
async def delete_user(
|
||||
user_id: UUID,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||
):
|
||||
"""Удалить пользователя"""
|
||||
await use_cases.delete_user(user_id)
|
||||
@ -116,9 +119,9 @@ async def delete_user(
|
||||
@router.get("", response_model=List[UserResponse])
|
||||
@inject
|
||||
async def list_users(
|
||||
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||
skip: int = 0,
|
||||
limit: int = 100,
|
||||
use_cases: UserUseCases = FromDishka()
|
||||
limit: int = 100
|
||||
):
|
||||
"""Получить список пользователей"""
|
||||
users = await use_cases.list_users(skip=skip, limit=limit)
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import os
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
backend_dir = Path(__file__).parent.parent.parent
|
||||
@ -24,15 +23,18 @@ from src.infrastructure.database.base import engine, Base
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
"""Управление жизненным циклом приложения"""
|
||||
container = create_container()
|
||||
setup_dishka(container, app)
|
||||
try:
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
except Exception as e:
|
||||
print(f"Примечание при создании таблиц: {e}")
|
||||
yield
|
||||
await container.close()
|
||||
# Cleanup container if needed
|
||||
if hasattr(app.state, 'container') and hasattr(app.state.container, 'close'):
|
||||
if asyncio.iscoroutinefunction(app.state.container.close):
|
||||
await app.state.container.close()
|
||||
else:
|
||||
app.state.container.close()
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@ -43,6 +45,11 @@ app = FastAPI(
|
||||
lifespan=lifespan
|
||||
)
|
||||
|
||||
# Настройка Dishka ДО добавления middleware
|
||||
container = create_container()
|
||||
setup_dishka(container, app)
|
||||
app.state.container = container
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=settings.CORS_ORIGINS,
|
||||
|
||||
@ -1,77 +1,77 @@
|
||||
"""
|
||||
Pydantic схемы для Collection
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class CollectionBase(BaseModel):
|
||||
"""Базовая схема коллекции"""
|
||||
name: str
|
||||
description: str = ""
|
||||
is_public: bool = False
|
||||
|
||||
|
||||
class CollectionCreate(CollectionBase):
|
||||
"""Схема создания коллекции"""
|
||||
pass
|
||||
|
||||
|
||||
class CollectionUpdate(BaseModel):
|
||||
"""Схема обновления коллекции"""
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
is_public: bool | None = None
|
||||
|
||||
|
||||
class CollectionResponse(BaseModel):
|
||||
"""Схема ответа с коллекцией"""
|
||||
collection_id: UUID
|
||||
name: str
|
||||
description: str
|
||||
owner_id: UUID
|
||||
is_public: bool
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, collection: "Collection") -> "CollectionResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
collection_id=collection.collection_id,
|
||||
name=collection.name,
|
||||
description=collection.description,
|
||||
owner_id=collection.owner_id,
|
||||
is_public=collection.is_public,
|
||||
created_at=collection.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CollectionAccessGrant(BaseModel):
|
||||
"""Схема предоставления доступа"""
|
||||
user_id: UUID
|
||||
|
||||
|
||||
class CollectionAccessResponse(BaseModel):
|
||||
"""Схема ответа с доступом"""
|
||||
access_id: UUID
|
||||
user_id: UUID
|
||||
collection_id: UUID
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, access: "CollectionAccess") -> "CollectionAccessResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
access_id=access.access_id,
|
||||
user_id=access.user_id,
|
||||
collection_id=access.collection_id,
|
||||
created_at=access.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
"""
|
||||
Pydantic схемы для Collection
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class CollectionBase(BaseModel):
|
||||
"""Базовая схема коллекции"""
|
||||
name: str
|
||||
description: str = ""
|
||||
is_public: bool = False
|
||||
|
||||
|
||||
class CollectionCreate(CollectionBase):
|
||||
"""Схема создания коллекции"""
|
||||
pass
|
||||
|
||||
|
||||
class CollectionUpdate(BaseModel):
|
||||
"""Схема обновления коллекции"""
|
||||
name: str | None = None
|
||||
description: str | None = None
|
||||
is_public: bool | None = None
|
||||
|
||||
|
||||
class CollectionResponse(BaseModel):
|
||||
"""Схема ответа с коллекцией"""
|
||||
collection_id: UUID
|
||||
name: str
|
||||
description: str
|
||||
owner_id: UUID
|
||||
is_public: bool
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, collection: "Collection") -> "CollectionResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
collection_id=collection.collection_id,
|
||||
name=collection.name,
|
||||
description=collection.description,
|
||||
owner_id=collection.owner_id,
|
||||
is_public=collection.is_public,
|
||||
created_at=collection.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class CollectionAccessGrant(BaseModel):
|
||||
"""Схема предоставления доступа"""
|
||||
user_id: UUID
|
||||
|
||||
|
||||
class CollectionAccessResponse(BaseModel):
|
||||
"""Схема ответа с доступом"""
|
||||
access_id: UUID
|
||||
user_id: UUID
|
||||
collection_id: UUID
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, access: "CollectionAccess") -> "CollectionAccessResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
access_id=access.access_id,
|
||||
user_id=access.user_id,
|
||||
collection_id=access.collection_id,
|
||||
created_at=access.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
"""
|
||||
Pydantic схемы для Conversation
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ConversationCreate(BaseModel):
|
||||
"""Схема создания беседы"""
|
||||
collection_id: UUID
|
||||
|
||||
|
||||
class ConversationResponse(BaseModel):
|
||||
"""Схема ответа с беседой"""
|
||||
conversation_id: UUID
|
||||
user_id: UUID
|
||||
collection_id: UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, conversation: "Conversation") -> "ConversationResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
conversation_id=conversation.conversation_id,
|
||||
user_id=conversation.user_id,
|
||||
collection_id=conversation.collection_id,
|
||||
created_at=conversation.created_at,
|
||||
updated_at=conversation.updated_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
"""
|
||||
Pydantic схемы для Conversation
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ConversationCreate(BaseModel):
|
||||
"""Схема создания беседы"""
|
||||
collection_id: UUID
|
||||
|
||||
|
||||
class ConversationResponse(BaseModel):
|
||||
"""Схема ответа с беседой"""
|
||||
conversation_id: UUID
|
||||
user_id: UUID
|
||||
collection_id: UUID
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, conversation: "Conversation") -> "ConversationResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
conversation_id=conversation.conversation_id,
|
||||
user_id=conversation.user_id,
|
||||
collection_id=conversation.collection_id,
|
||||
created_at=conversation.created_at,
|
||||
updated_at=conversation.updated_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@ -1,52 +1,52 @@
|
||||
"""
|
||||
Pydantic схемы для Document
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DocumentBase(BaseModel):
|
||||
"""Базовая схема документа"""
|
||||
title: str
|
||||
content: str
|
||||
metadata: dict[str, Any] = {}
|
||||
|
||||
|
||||
class DocumentCreate(DocumentBase):
|
||||
"""Схема создания документа"""
|
||||
collection_id: UUID
|
||||
|
||||
|
||||
class DocumentUpdate(BaseModel):
|
||||
"""Схема обновления документа"""
|
||||
title: str | None = None
|
||||
content: str | None = None
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class DocumentResponse(BaseModel):
|
||||
"""Схема ответа с документом"""
|
||||
document_id: UUID
|
||||
collection_id: UUID
|
||||
title: str
|
||||
content: str
|
||||
metadata: dict[str, Any]
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, document: "Document") -> "DocumentResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
document_id=document.document_id,
|
||||
collection_id=document.collection_id,
|
||||
title=document.title,
|
||||
content=document.content,
|
||||
metadata=document.metadata,
|
||||
created_at=document.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
"""
|
||||
Pydantic схемы для Document
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class DocumentBase(BaseModel):
|
||||
"""Базовая схема документа"""
|
||||
title: str
|
||||
content: str
|
||||
metadata: dict[str, Any] = {}
|
||||
|
||||
|
||||
class DocumentCreate(DocumentBase):
|
||||
"""Схема создания документа"""
|
||||
collection_id: UUID
|
||||
|
||||
|
||||
class DocumentUpdate(BaseModel):
|
||||
"""Схема обновления документа"""
|
||||
title: str | None = None
|
||||
content: str | None = None
|
||||
metadata: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class DocumentResponse(BaseModel):
|
||||
"""Схема ответа с документом"""
|
||||
document_id: UUID
|
||||
collection_id: UUID
|
||||
title: str
|
||||
content: str
|
||||
metadata: dict[str, Any]
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, document: "Document") -> "DocumentResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
document_id=document.document_id,
|
||||
collection_id=document.collection_id,
|
||||
title=document.title,
|
||||
content=document.content,
|
||||
metadata=document.metadata,
|
||||
created_at=document.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@ -1,52 +1,52 @@
|
||||
"""
|
||||
Pydantic схемы для Message
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from pydantic import BaseModel
|
||||
from src.domain.entities.message import MessageRole
|
||||
|
||||
|
||||
class MessageBase(BaseModel):
|
||||
"""Базовая схема сообщения"""
|
||||
content: str
|
||||
role: MessageRole
|
||||
sources: dict[str, Any] = {}
|
||||
|
||||
|
||||
class MessageCreate(MessageBase):
|
||||
"""Схема создания сообщения"""
|
||||
conversation_id: UUID
|
||||
|
||||
|
||||
class MessageUpdate(BaseModel):
|
||||
"""Схема обновления сообщения"""
|
||||
content: str | None = None
|
||||
sources: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class MessageResponse(BaseModel):
|
||||
"""Схема ответа с сообщением"""
|
||||
message_id: UUID
|
||||
conversation_id: UUID
|
||||
content: str
|
||||
role: MessageRole
|
||||
sources: dict[str, Any]
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, message: "Message") -> "MessageResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
message_id=message.message_id,
|
||||
conversation_id=message.conversation_id,
|
||||
content=message.content,
|
||||
role=message.role,
|
||||
sources=message.sources,
|
||||
created_at=message.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
"""
|
||||
Pydantic схемы для Message
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from typing import Any
|
||||
from pydantic import BaseModel
|
||||
from src.domain.entities.message import MessageRole
|
||||
|
||||
|
||||
class MessageBase(BaseModel):
|
||||
"""Базовая схема сообщения"""
|
||||
content: str
|
||||
role: MessageRole
|
||||
sources: dict[str, Any] = {}
|
||||
|
||||
|
||||
class MessageCreate(MessageBase):
|
||||
"""Схема создания сообщения"""
|
||||
conversation_id: UUID
|
||||
|
||||
|
||||
class MessageUpdate(BaseModel):
|
||||
"""Схема обновления сообщения"""
|
||||
content: str | None = None
|
||||
sources: dict[str, Any] | None = None
|
||||
|
||||
|
||||
class MessageResponse(BaseModel):
|
||||
"""Схема ответа с сообщением"""
|
||||
message_id: UUID
|
||||
conversation_id: UUID
|
||||
content: str
|
||||
role: MessageRole
|
||||
sources: dict[str, Any]
|
||||
created_at: datetime
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, message: "Message") -> "MessageResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
message_id=message.message_id,
|
||||
conversation_id=message.conversation_id,
|
||||
content=message.content,
|
||||
role=message.role,
|
||||
sources=message.sources,
|
||||
created_at=message.created_at
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@ -1,52 +1,52 @@
|
||||
"""
|
||||
Pydantic схемы для User
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
from src.domain.entities.user import UserRole
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
"""Базовая схема пользователя"""
|
||||
telegram_id: str
|
||||
role: UserRole
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
"""Схема создания пользователя"""
|
||||
pass
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
"""Схема обновления пользователя"""
|
||||
telegram_id: str | None = None
|
||||
role: UserRole | None = None
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
"""Схема ответа с пользователем"""
|
||||
user_id: UUID
|
||||
telegram_id: str
|
||||
role: UserRole
|
||||
created_at: datetime
|
||||
is_premium: bool = False
|
||||
premium_until: datetime | None = None
|
||||
questions_used: int = 0
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, user: "User") -> "UserResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
user_id=user.user_id,
|
||||
telegram_id=user.telegram_id,
|
||||
role=user.role,
|
||||
created_at=user.created_at,
|
||||
is_premium=user.is_premium,
|
||||
premium_until=user.premium_until,
|
||||
questions_used=user.questions_used
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
"""
|
||||
Pydantic схемы для User
|
||||
"""
|
||||
from uuid import UUID
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel
|
||||
from src.domain.entities.user import UserRole
|
||||
|
||||
|
||||
class UserBase(BaseModel):
|
||||
"""Базовая схема пользователя"""
|
||||
telegram_id: str
|
||||
role: UserRole
|
||||
|
||||
|
||||
class UserCreate(UserBase):
|
||||
"""Схема создания пользователя"""
|
||||
pass
|
||||
|
||||
|
||||
class UserUpdate(BaseModel):
|
||||
"""Схема обновления пользователя"""
|
||||
telegram_id: str | None = None
|
||||
role: UserRole | None = None
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
"""Схема ответа с пользователем"""
|
||||
user_id: UUID
|
||||
telegram_id: str
|
||||
role: UserRole
|
||||
created_at: datetime
|
||||
is_premium: bool = False
|
||||
premium_until: datetime | None = None
|
||||
questions_used: int = 0
|
||||
|
||||
@classmethod
|
||||
def from_entity(cls, user: "User") -> "UserResponse":
|
||||
"""Создать из доменной сущности"""
|
||||
return cls(
|
||||
user_id=user.user_id,
|
||||
telegram_id=user.telegram_id,
|
||||
role=user.role,
|
||||
created_at=user.created_at,
|
||||
is_premium=user.is_premium,
|
||||
premium_until=user.premium_until,
|
||||
questions_used=user.questions_used
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@ -7,18 +7,19 @@ from typing import Optional
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Настройки (загружаются из .env автоматически)"""
|
||||
|
||||
POSTGRES_HOST: str
|
||||
POSTGRES_PORT: int
|
||||
POSTGRES_USER: str
|
||||
POSTGRES_PASSWORD: str
|
||||
POSTGRES_DB: str
|
||||
POSTGRES_HOST: str = "localhost"
|
||||
POSTGRES_PORT: int = 5432
|
||||
POSTGRES_USER: str = "postgres"
|
||||
POSTGRES_PASSWORD: str = "postgres"
|
||||
POSTGRES_DB: str = "lawyer_ai"
|
||||
|
||||
QDRANT_HOST: str
|
||||
QDRANT_PORT: int
|
||||
QDRANT_HOST: str = "localhost"
|
||||
QDRANT_PORT: int = 6333
|
||||
|
||||
REDIS_HOST: str
|
||||
REDIS_PORT: int
|
||||
REDIS_HOST: str = "localhost"
|
||||
REDIS_PORT: int = 6379
|
||||
|
||||
TELEGRAM_BOT_TOKEN: Optional[str] = None
|
||||
YANDEX_OCR_API_KEY: Optional[str] = None
|
||||
@ -29,11 +30,12 @@ class Settings(BaseSettings):
|
||||
|
||||
APP_NAME: str = "ИИ-юрист"
|
||||
DEBUG: bool = False
|
||||
SECRET_KEY: str
|
||||
SECRET_KEY: str = "your-secret-key-change-in-production"
|
||||
CORS_ORIGINS: list[str] = ["*"]
|
||||
|
||||
@property
|
||||
def database_url(self) -> str:
|
||||
"""Вычисляемый URL подключения"""
|
||||
return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
||||
|
||||
class Config:
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from dishka import Container, Provider, Scope, provide
|
||||
from dishka import Container, Provider, Scope, provide, make_async_container
|
||||
from fastapi import Request
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from collections.abc import AsyncIterator
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from src.infrastructure.database.base import AsyncSessionLocal
|
||||
from src.infrastructure.repositories.postgresql.user_repository import PostgreSQLUserRepository
|
||||
@ -39,7 +39,8 @@ from src.application.use_cases.rag_use_cases import RAGUseCases
|
||||
|
||||
class DatabaseProvider(Provider):
|
||||
@provide(scope=Scope.REQUEST)
|
||||
async def get_db(self) -> AsyncIterator[AsyncSession]:
|
||||
@asynccontextmanager
|
||||
async def get_db(self) -> AsyncSession:
|
||||
async with AsyncSessionLocal() as session:
|
||||
try:
|
||||
yield session
|
||||
@ -94,8 +95,6 @@ class ServiceProvider(Provider):
|
||||
def get_parser_service(self, ocr_service: YandexOCRService) -> DocumentParserService:
|
||||
return DocumentParserService(ocr_service)
|
||||
|
||||
|
||||
class VectorServiceProvider(Provider):
|
||||
@provide(scope=Scope.APP)
|
||||
def get_qdrant_client(self) -> QdrantClient:
|
||||
return QdrantClient(host=settings.QDRANT_HOST, port=settings.QDRANT_PORT)
|
||||
@ -133,12 +132,6 @@ class VectorServiceProvider(Provider):
|
||||
splitter=text_splitter,
|
||||
)
|
||||
|
||||
class AuthProvider(Provider):
|
||||
@provide(scope=Scope.REQUEST)
|
||||
async def get_current_user(self, request: Request, user_repo: IUserRepository) -> User:
|
||||
from src.presentation.middleware.auth_middleware import get_current_user
|
||||
return await get_current_user(request, user_repo)
|
||||
|
||||
|
||||
class UseCaseProvider(Provider):
|
||||
@provide(scope=Scope.REQUEST)
|
||||
@ -196,12 +189,10 @@ class UseCaseProvider(Provider):
|
||||
|
||||
|
||||
def create_container() -> Container:
|
||||
container = Container()
|
||||
container.add_provider(DatabaseProvider())
|
||||
container.add_provider(RepositoryProvider())
|
||||
container.add_provider(ServiceProvider())
|
||||
container.add_provider(AuthProvider())
|
||||
container.add_provider(UseCaseProvider())
|
||||
container.add_provider(VectorServiceProvider())
|
||||
return container
|
||||
return make_async_container(
|
||||
DatabaseProvider(),
|
||||
RepositoryProvider(),
|
||||
ServiceProvider(),
|
||||
UseCaseProvider()
|
||||
)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user