andrewbokh #6
@ -9,7 +9,7 @@ python-multipart==0.0.6
|
|||||||
httpx==0.25.2
|
httpx==0.25.2
|
||||||
PyMuPDF==1.23.8
|
PyMuPDF==1.23.8
|
||||||
Pillow==10.2.0
|
Pillow==10.2.0
|
||||||
dishka==1.7.2
|
dishka==0.7.0
|
||||||
numpy==1.26.4
|
numpy==1.26.4
|
||||||
sentence-transformers==2.7.0
|
sentence-transformers==2.7.0
|
||||||
qdrant-client==1.9.0
|
qdrant-client==1.9.0
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class CacheService:
|
|||||||
"question": question,
|
"question": question,
|
||||||
"answer": answer
|
"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):
|
async def invalidate_collection_cache(self, collection_id: UUID):
|
||||||
pattern = f"rag:answer:{collection_id}:*"
|
pattern = f"rag:answer:{collection_id}:*"
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
Админ-панель - упрощенная версия через API эндпоинты
|
Админ-панель - упрощенная версия через API эндпоинты
|
||||||
В будущем можно интегрировать полноценную админ-панель
|
В будущем можно интегрировать полноценную админ-панель
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from fastapi import APIRouter, HTTPException, Request
|
||||||
|
from typing import List, Annotated
|
||||||
from fastapi import APIRouter, HTTPException
|
|
||||||
from typing import List
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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.user_schemas import UserResponse
|
||||||
from src.presentation.schemas.collection_schemas import CollectionResponse
|
from src.presentation.schemas.collection_schemas import CollectionResponse
|
||||||
from src.presentation.schemas.document_schemas import DocumentResponse
|
from src.presentation.schemas.document_schemas import DocumentResponse
|
||||||
@ -21,13 +21,16 @@ router = APIRouter(prefix="/admin", tags=["admin"])
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/users", response_model=List[UserResponse])
|
@router.get("/users", response_model=List[UserResponse])
|
||||||
|
@inject
|
||||||
async def admin_list_users(
|
async def admin_list_users(
|
||||||
|
request: Request,
|
||||||
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
current_user: User = FromDishka(),
|
|
||||||
use_cases: UserUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить список всех пользователей (только для админов)"""
|
"""Получить список всех пользователей (только для админов)"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
if not current_user.is_admin():
|
if not current_user.is_admin():
|
||||||
raise HTTPException(status_code=403, detail="Требуются права администратора")
|
raise HTTPException(status_code=403, detail="Требуются права администратора")
|
||||||
users = await use_cases.list_users(skip=skip, limit=limit)
|
users = await use_cases.list_users(skip=skip, limit=limit)
|
||||||
@ -35,13 +38,16 @@ async def admin_list_users(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/collections", response_model=List[CollectionResponse])
|
@router.get("/collections", response_model=List[CollectionResponse])
|
||||||
|
@inject
|
||||||
async def admin_list_collections(
|
async def admin_list_collections(
|
||||||
|
request: Request,
|
||||||
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[CollectionUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
current_user: User = FromDishka(),
|
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить список всех коллекций (только для админов)"""
|
"""Получить список всех коллекций (только для админов)"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
from src.infrastructure.database.base import AsyncSessionLocal
|
from src.infrastructure.database.base import AsyncSessionLocal
|
||||||
from src.infrastructure.repositories.postgresql.collection_repository import PostgreSQLCollectionRepository
|
from src.infrastructure.repositories.postgresql.collection_repository import PostgreSQLCollectionRepository
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
API роутеры для работы с коллекциями
|
API роутеры для работы с коллекциями
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, status
|
from fastapi import APIRouter, status, Depends, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from typing import List
|
from typing import List, Annotated
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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 (
|
from src.presentation.schemas.collection_schemas import (
|
||||||
CollectionCreate,
|
CollectionCreate,
|
||||||
CollectionUpdate,
|
CollectionUpdate,
|
||||||
@ -22,12 +22,15 @@ router = APIRouter(prefix="/collections", tags=["collections"])
|
|||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=CollectionResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("", response_model=CollectionResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def create_collection(
|
async def create_collection(
|
||||||
collection_data: CollectionCreate,
|
collection_data: CollectionCreate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
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(
|
collection = await use_cases.create_collection(
|
||||||
name=collection_data.name,
|
name=collection_data.name,
|
||||||
owner_id=current_user.user_id,
|
owner_id=current_user.user_id,
|
||||||
@ -38,9 +41,10 @@ async def create_collection(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/{collection_id}", response_model=CollectionResponse)
|
@router.get("/{collection_id}", response_model=CollectionResponse)
|
||||||
|
@inject
|
||||||
async def get_collection(
|
async def get_collection(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
use_cases: Annotated[CollectionUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить коллекцию по ID"""
|
"""Получить коллекцию по ID"""
|
||||||
collection = await use_cases.get_collection(collection_id)
|
collection = await use_cases.get_collection(collection_id)
|
||||||
@ -48,13 +52,16 @@ async def get_collection(
|
|||||||
|
|
||||||
|
|
||||||
@router.put("/{collection_id}", response_model=CollectionResponse)
|
@router.put("/{collection_id}", response_model=CollectionResponse)
|
||||||
|
@inject
|
||||||
async def update_collection(
|
async def update_collection(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
collection_data: CollectionUpdate,
|
collection_data: CollectionUpdate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
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 = await use_cases.update_collection(
|
||||||
collection_id=collection_id,
|
collection_id=collection_id,
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
@ -66,24 +73,30 @@ async def update_collection(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete("/{collection_id}", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{collection_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
@inject
|
||||||
async def delete_collection(
|
async def delete_collection(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
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)
|
await use_cases.delete_collection(collection_id, current_user.user_id)
|
||||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||||
|
|
||||||
|
|
||||||
@router.get("", response_model=List[CollectionResponse])
|
@router.get("", response_model=List[CollectionResponse])
|
||||||
|
@inject
|
||||||
async def list_collections(
|
async def list_collections(
|
||||||
|
request: Request,
|
||||||
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[CollectionUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
current_user: User = FromDishka(),
|
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить список коллекций, доступных пользователю"""
|
"""Получить список коллекций, доступных пользователю"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
collections = await use_cases.list_user_collections(
|
collections = await use_cases.list_user_collections(
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
skip=skip,
|
skip=skip,
|
||||||
@ -93,13 +106,16 @@ async def list_collections(
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/{collection_id}/access", response_model=CollectionAccessResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("/{collection_id}/access", response_model=CollectionAccessResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def grant_access(
|
async def grant_access(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
access_data: CollectionAccessGrant,
|
access_data: CollectionAccessGrant,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
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(
|
access = await use_cases.grant_access(
|
||||||
collection_id=collection_id,
|
collection_id=collection_id,
|
||||||
user_id=access_data.user_id,
|
user_id=access_data.user_id,
|
||||||
@ -109,13 +125,16 @@ async def grant_access(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete("/{collection_id}/access/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{collection_id}/access/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
@inject
|
||||||
async def revoke_access(
|
async def revoke_access(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
user_id: UUID,
|
user_id: UUID,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: CollectionUseCases = FromDishka()
|
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)
|
await use_cases.revoke_access(collection_id, user_id, current_user.user_id)
|
||||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
API роутеры для работы с беседами
|
API роутеры для работы с беседами
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, status
|
from fastapi import APIRouter, status, Depends, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from typing import List
|
from typing import List, Annotated
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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 (
|
from src.presentation.schemas.conversation_schemas import (
|
||||||
ConversationCreate,
|
ConversationCreate,
|
||||||
ConversationResponse
|
ConversationResponse
|
||||||
@ -19,12 +19,15 @@ router = APIRouter(prefix="/conversations", tags=["conversations"])
|
|||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=ConversationResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("", response_model=ConversationResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def create_conversation(
|
async def create_conversation(
|
||||||
conversation_data: ConversationCreate,
|
conversation_data: ConversationCreate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: ConversationUseCases = FromDishka()
|
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(
|
conversation = await use_cases.create_conversation(
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
collection_id=conversation_data.collection_id
|
collection_id=conversation_data.collection_id
|
||||||
@ -33,35 +36,44 @@ async def create_conversation(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/{conversation_id}", response_model=ConversationResponse)
|
@router.get("/{conversation_id}", response_model=ConversationResponse)
|
||||||
|
@inject
|
||||||
async def get_conversation(
|
async def get_conversation(
|
||||||
conversation_id: UUID,
|
conversation_id: UUID,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: ConversationUseCases = FromDishka()
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[ConversationUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить беседу по ID"""
|
"""Получить беседу по ID"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
conversation = await use_cases.get_conversation(conversation_id, current_user.user_id)
|
conversation = await use_cases.get_conversation(conversation_id, current_user.user_id)
|
||||||
return ConversationResponse.from_entity(conversation)
|
return ConversationResponse.from_entity(conversation)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{conversation_id}", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{conversation_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
@inject
|
||||||
async def delete_conversation(
|
async def delete_conversation(
|
||||||
conversation_id: UUID,
|
conversation_id: UUID,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: ConversationUseCases = FromDishka()
|
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)
|
await use_cases.delete_conversation(conversation_id, current_user.user_id)
|
||||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||||
|
|
||||||
|
|
||||||
@router.get("", response_model=List[ConversationResponse])
|
@router.get("", response_model=List[ConversationResponse])
|
||||||
|
@inject
|
||||||
async def list_conversations(
|
async def list_conversations(
|
||||||
|
request: Request,
|
||||||
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[ConversationUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
current_user: User = FromDishka(),
|
|
||||||
use_cases: ConversationUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить список бесед пользователя"""
|
"""Получить список бесед пользователя"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
conversations = await use_cases.list_user_conversations(
|
conversations = await use_cases.list_user_conversations(
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
skip=skip,
|
skip=skip,
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
API роутеры для работы с документами
|
API роутеры для работы с документами
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, status, UploadFile, File
|
from fastapi import APIRouter, status, UploadFile, File, Depends, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from typing import List
|
from typing import List, Annotated
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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 (
|
from src.presentation.schemas.document_schemas import (
|
||||||
DocumentCreate,
|
DocumentCreate,
|
||||||
DocumentUpdate,
|
DocumentUpdate,
|
||||||
@ -20,12 +20,15 @@ router = APIRouter(prefix="/documents", tags=["documents"])
|
|||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def create_document(
|
async def create_document(
|
||||||
document_data: DocumentCreate,
|
document_data: DocumentCreate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
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(
|
document = await use_cases.create_document(
|
||||||
collection_id=document_data.collection_id,
|
collection_id=document_data.collection_id,
|
||||||
title=document_data.title,
|
title=document_data.title,
|
||||||
@ -36,13 +39,16 @@ async def create_document(
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("/upload", response_model=DocumentResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def upload_document(
|
async def upload_document(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
file: UploadFile = File(...),
|
request: Request,
|
||||||
current_user: User = FromDishka(),
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
use_cases: Annotated[DocumentUseCases, FromDishka()],
|
||||||
|
file: UploadFile = File(...)
|
||||||
):
|
):
|
||||||
"""Загрузить и распарсить PDF документ или изображение"""
|
"""Загрузить и распарсить PDF документ или изображение"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
if not file.filename:
|
if not file.filename:
|
||||||
raise JSONResponse(
|
raise JSONResponse(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST,
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
@ -68,9 +74,10 @@ async def upload_document(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/{document_id}", response_model=DocumentResponse)
|
@router.get("/{document_id}", response_model=DocumentResponse)
|
||||||
|
@inject
|
||||||
async def get_document(
|
async def get_document(
|
||||||
document_id: UUID,
|
document_id: UUID,
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
use_cases: Annotated[DocumentUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить документ по ID"""
|
"""Получить документ по ID"""
|
||||||
document = await use_cases.get_document(document_id)
|
document = await use_cases.get_document(document_id)
|
||||||
@ -78,13 +85,16 @@ async def get_document(
|
|||||||
|
|
||||||
|
|
||||||
@router.put("/{document_id}", response_model=DocumentResponse)
|
@router.put("/{document_id}", response_model=DocumentResponse)
|
||||||
|
@inject
|
||||||
async def update_document(
|
async def update_document(
|
||||||
document_id: UUID,
|
document_id: UUID,
|
||||||
document_data: DocumentUpdate,
|
document_data: DocumentUpdate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
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 = await use_cases.update_document(
|
||||||
document_id=document_id,
|
document_id=document_id,
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
@ -96,22 +106,26 @@ async def update_document(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{document_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
@inject
|
||||||
async def delete_document(
|
async def delete_document(
|
||||||
document_id: UUID,
|
document_id: UUID,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
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)
|
await use_cases.delete_document(document_id, current_user.user_id)
|
||||||
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT, content=None)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/collection/{collection_id}", response_model=List[DocumentResponse])
|
@router.get("/collection/{collection_id}", response_model=List[DocumentResponse])
|
||||||
|
@inject
|
||||||
async def list_collection_documents(
|
async def list_collection_documents(
|
||||||
collection_id: UUID,
|
collection_id: UUID,
|
||||||
|
use_cases: Annotated[DocumentUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
use_cases: DocumentUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить документы коллекции"""
|
"""Получить документы коллекции"""
|
||||||
documents = await use_cases.list_collection_documents(
|
documents = await use_cases.list_collection_documents(
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
API роутеры для работы с сообщениями
|
API роутеры для работы с сообщениями
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, status
|
from fastapi import APIRouter, status, Depends, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from typing import List
|
from typing import List, Annotated
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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 (
|
from src.presentation.schemas.message_schemas import (
|
||||||
MessageCreate,
|
MessageCreate,
|
||||||
MessageUpdate,
|
MessageUpdate,
|
||||||
@ -20,12 +20,15 @@ router = APIRouter(prefix="/messages", tags=["messages"])
|
|||||||
|
|
||||||
|
|
||||||
@router.post("", response_model=MessageResponse, status_code=status.HTTP_201_CREATED)
|
@router.post("", response_model=MessageResponse, status_code=status.HTTP_201_CREATED)
|
||||||
|
@inject
|
||||||
async def create_message(
|
async def create_message(
|
||||||
message_data: MessageCreate,
|
message_data: MessageCreate,
|
||||||
current_user: User = FromDishka(),
|
request: Request,
|
||||||
use_cases: MessageUseCases = FromDishka()
|
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(
|
message = await use_cases.create_message(
|
||||||
conversation_id=message_data.conversation_id,
|
conversation_id=message_data.conversation_id,
|
||||||
content=message_data.content,
|
content=message_data.content,
|
||||||
@ -37,9 +40,10 @@ async def create_message(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/{message_id}", response_model=MessageResponse)
|
@router.get("/{message_id}", response_model=MessageResponse)
|
||||||
|
@inject
|
||||||
async def get_message(
|
async def get_message(
|
||||||
message_id: UUID,
|
message_id: UUID,
|
||||||
use_cases: MessageUseCases = FromDishka()
|
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить сообщение по ID"""
|
"""Получить сообщение по ID"""
|
||||||
message = await use_cases.get_message(message_id)
|
message = await use_cases.get_message(message_id)
|
||||||
@ -47,10 +51,11 @@ async def get_message(
|
|||||||
|
|
||||||
|
|
||||||
@router.put("/{message_id}", response_model=MessageResponse)
|
@router.put("/{message_id}", response_model=MessageResponse)
|
||||||
|
@inject
|
||||||
async def update_message(
|
async def update_message(
|
||||||
message_id: UUID,
|
message_id: UUID,
|
||||||
message_data: MessageUpdate,
|
message_data: MessageUpdate,
|
||||||
use_cases: MessageUseCases = FromDishka()
|
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Обновить сообщение"""
|
"""Обновить сообщение"""
|
||||||
message = await use_cases.update_message(
|
message = await use_cases.update_message(
|
||||||
@ -62,9 +67,10 @@ async def update_message(
|
|||||||
|
|
||||||
|
|
||||||
@router.delete("/{message_id}", status_code=status.HTTP_204_NO_CONTENT)
|
@router.delete("/{message_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||||
|
@inject
|
||||||
async def delete_message(
|
async def delete_message(
|
||||||
message_id: UUID,
|
message_id: UUID,
|
||||||
use_cases: MessageUseCases = FromDishka()
|
use_cases: Annotated[MessageUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Удалить сообщение"""
|
"""Удалить сообщение"""
|
||||||
await use_cases.delete_message(message_id)
|
await use_cases.delete_message(message_id)
|
||||||
@ -72,14 +78,17 @@ async def delete_message(
|
|||||||
|
|
||||||
|
|
||||||
@router.get("/conversation/{conversation_id}", response_model=List[MessageResponse])
|
@router.get("/conversation/{conversation_id}", response_model=List[MessageResponse])
|
||||||
|
@inject
|
||||||
async def list_conversation_messages(
|
async def list_conversation_messages(
|
||||||
conversation_id: UUID,
|
conversation_id: UUID,
|
||||||
|
request: Request,
|
||||||
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[MessageUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
current_user: User = FromDishka(),
|
|
||||||
use_cases: MessageUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить сообщения беседы"""
|
"""Получить сообщения беседы"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
messages = await use_cases.list_conversation_messages(
|
messages = await use_cases.list_conversation_messages(
|
||||||
conversation_id=conversation_id,
|
conversation_id=conversation_id,
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
"""
|
"""
|
||||||
API для RAG: индексация документов и ответы на вопросы
|
API для RAG: индексация документов и ответы на вопросы
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from fastapi import APIRouter, status, Request
|
||||||
|
from typing import Annotated
|
||||||
from fastapi import APIRouter, status
|
from dishka.integrations.fastapi import FromDishka, inject
|
||||||
from dishka.integrations.fastapi import FromDishka
|
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 (
|
from src.presentation.schemas.rag_schemas import (
|
||||||
QuestionRequest,
|
QuestionRequest,
|
||||||
RAGAnswer,
|
RAGAnswer,
|
||||||
@ -19,23 +20,29 @@ router = APIRouter(prefix="/rag", tags=["rag"])
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/index", response_model=IndexDocumentResponse, status_code=status.HTTP_200_OK)
|
@router.post("/index", response_model=IndexDocumentResponse, status_code=status.HTTP_200_OK)
|
||||||
|
@inject
|
||||||
async def index_document(
|
async def index_document(
|
||||||
body: IndexDocumentRequest,
|
body: IndexDocumentRequest,
|
||||||
use_cases: RAGUseCases = FromDishka(),
|
request: Request,
|
||||||
current_user: User = FromDishka(),
|
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)
|
result = await use_cases.index_document(body.document_id)
|
||||||
return IndexDocumentResponse(**result)
|
return IndexDocumentResponse(**result)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/question", response_model=RAGAnswer, status_code=status.HTTP_200_OK)
|
@router.post("/question", response_model=RAGAnswer, status_code=status.HTTP_200_OK)
|
||||||
|
@inject
|
||||||
async def ask_question(
|
async def ask_question(
|
||||||
body: QuestionRequest,
|
body: QuestionRequest,
|
||||||
use_cases: RAGUseCases = FromDishka(),
|
request: Request,
|
||||||
current_user: User = FromDishka(),
|
user_repo: Annotated[IUserRepository, FromDishka()],
|
||||||
|
use_cases: Annotated[RAGUseCases, FromDishka()],
|
||||||
):
|
):
|
||||||
"""Отвечает на вопрос, используя RAG в рамках беседы"""
|
"""Отвечает на вопрос, используя RAG в рамках беседы"""
|
||||||
|
current_user = await get_current_user(request, user_repo)
|
||||||
result = await use_cases.ask_question(
|
result = await use_cases.ask_question(
|
||||||
conversation_id=body.conversation_id,
|
conversation_id=body.conversation_id,
|
||||||
user_id=current_user.user_id,
|
user_id=current_user.user_id,
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
"""
|
"""
|
||||||
API роутеры для работы с пользователями
|
API роутеры для работы с пользователями
|
||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from fastapi import APIRouter, status, Depends
|
from fastapi import APIRouter, status, Depends, Request
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from typing import List, Annotated
|
from typing import List, Annotated
|
||||||
from dishka.integrations.fastapi import FromDishka, inject
|
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.presentation.schemas.user_schemas import UserCreate, UserUpdate, UserResponse
|
||||||
from src.application.use_cases.user_use_cases import UserUseCases
|
from src.application.use_cases.user_use_cases import UserUseCases
|
||||||
from src.domain.entities.user import User
|
from src.domain.entities.user import User
|
||||||
@ -19,8 +19,8 @@ router = APIRouter(prefix="/users", tags=["users"])
|
|||||||
@inject
|
@inject
|
||||||
async def create_user(
|
async def create_user(
|
||||||
user_data: UserCreate,
|
user_data: UserCreate,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
) -> UserResponse:
|
):
|
||||||
"""Создать пользователя"""
|
"""Создать пользователя"""
|
||||||
user = await use_cases.create_user(
|
user = await use_cases.create_user(
|
||||||
telegram_id=user_data.telegram_id,
|
telegram_id=user_data.telegram_id,
|
||||||
@ -32,9 +32,11 @@ async def create_user(
|
|||||||
@router.get("/me", response_model=UserResponse)
|
@router.get("/me", response_model=UserResponse)
|
||||||
@inject
|
@inject
|
||||||
async def get_current_user_info(
|
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)
|
return UserResponse.from_entity(current_user)
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +44,7 @@ async def get_current_user_info(
|
|||||||
@inject
|
@inject
|
||||||
async def get_user_by_telegram_id(
|
async def get_user_by_telegram_id(
|
||||||
telegram_id: str,
|
telegram_id: str,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить пользователя по Telegram ID"""
|
"""Получить пользователя по Telegram ID"""
|
||||||
user = await use_cases.get_user_by_telegram_id(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
|
@inject
|
||||||
async def increment_questions(
|
async def increment_questions(
|
||||||
telegram_id: str,
|
telegram_id: str,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Увеличить счетчик использованных вопросов"""
|
"""Увеличить счетчик использованных вопросов"""
|
||||||
user = await use_cases.increment_questions_used(telegram_id)
|
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)
|
@router.post("/telegram/{telegram_id}/activate-premium", response_model=UserResponse)
|
||||||
@inject
|
@inject
|
||||||
async def activate_premium(
|
async def activate_premium(
|
||||||
|
|
||||||
|
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||||
telegram_id: str,
|
telegram_id: str,
|
||||||
days: int = 30,
|
days: int = 30,
|
||||||
use_cases: UserUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Активировать premium статус"""
|
"""Активировать premium статус"""
|
||||||
user = await use_cases.activate_premium(telegram_id, days=days)
|
user = await use_cases.activate_premium(telegram_id, days=days)
|
||||||
@ -79,7 +82,7 @@ async def activate_premium(
|
|||||||
@inject
|
@inject
|
||||||
async def get_user(
|
async def get_user(
|
||||||
user_id: UUID,
|
user_id: UUID,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Получить пользователя по ID"""
|
"""Получить пользователя по ID"""
|
||||||
user = await use_cases.get_user(user_id)
|
user = await use_cases.get_user(user_id)
|
||||||
@ -91,7 +94,7 @@ async def get_user(
|
|||||||
async def update_user(
|
async def update_user(
|
||||||
user_id: UUID,
|
user_id: UUID,
|
||||||
user_data: UserUpdate,
|
user_data: UserUpdate,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Обновить пользователя"""
|
"""Обновить пользователя"""
|
||||||
user = await use_cases.update_user(
|
user = await use_cases.update_user(
|
||||||
@ -106,7 +109,7 @@ async def update_user(
|
|||||||
@inject
|
@inject
|
||||||
async def delete_user(
|
async def delete_user(
|
||||||
user_id: UUID,
|
user_id: UUID,
|
||||||
use_cases: UserUseCases = FromDishka()
|
use_cases: Annotated[UserUseCases, FromDishka()]
|
||||||
):
|
):
|
||||||
"""Удалить пользователя"""
|
"""Удалить пользователя"""
|
||||||
await use_cases.delete_user(user_id)
|
await use_cases.delete_user(user_id)
|
||||||
@ -116,9 +119,9 @@ async def delete_user(
|
|||||||
@router.get("", response_model=List[UserResponse])
|
@router.get("", response_model=List[UserResponse])
|
||||||
@inject
|
@inject
|
||||||
async def list_users(
|
async def list_users(
|
||||||
|
use_cases: Annotated[UserUseCases, FromDishka()],
|
||||||
skip: int = 0,
|
skip: int = 0,
|
||||||
limit: int = 100,
|
limit: int = 100
|
||||||
use_cases: UserUseCases = FromDishka()
|
|
||||||
):
|
):
|
||||||
"""Получить список пользователей"""
|
"""Получить список пользователей"""
|
||||||
users = await use_cases.list_users(skip=skip, limit=limit)
|
users = await use_cases.list_users(skip=skip, limit=limit)
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
from __future__ import annotations
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
backend_dir = Path(__file__).parent.parent.parent
|
backend_dir = Path(__file__).parent.parent.parent
|
||||||
@ -24,15 +23,18 @@ from src.infrastructure.database.base import engine, Base
|
|||||||
@asynccontextmanager
|
@asynccontextmanager
|
||||||
async def lifespan(app: FastAPI):
|
async def lifespan(app: FastAPI):
|
||||||
"""Управление жизненным циклом приложения"""
|
"""Управление жизненным циклом приложения"""
|
||||||
container = create_container()
|
|
||||||
setup_dishka(container, app)
|
|
||||||
try:
|
try:
|
||||||
async with engine.begin() as conn:
|
async with engine.begin() as conn:
|
||||||
await conn.run_sync(Base.metadata.create_all)
|
await conn.run_sync(Base.metadata.create_all)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Примечание при создании таблиц: {e}")
|
print(f"Примечание при создании таблиц: {e}")
|
||||||
yield
|
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()
|
await engine.dispose()
|
||||||
|
|
||||||
|
|
||||||
@ -43,6 +45,11 @@ app = FastAPI(
|
|||||||
lifespan=lifespan
|
lifespan=lifespan
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Настройка Dishka ДО добавления middleware
|
||||||
|
container = create_container()
|
||||||
|
setup_dishka(container, app)
|
||||||
|
app.state.container = container
|
||||||
|
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
allow_origins=settings.CORS_ORIGINS,
|
allow_origins=settings.CORS_ORIGINS,
|
||||||
|
|||||||
@ -7,18 +7,19 @@ from typing import Optional
|
|||||||
|
|
||||||
|
|
||||||
class Settings(BaseSettings):
|
class Settings(BaseSettings):
|
||||||
|
"""Настройки (загружаются из .env автоматически)"""
|
||||||
|
|
||||||
POSTGRES_HOST: str
|
POSTGRES_HOST: str = "localhost"
|
||||||
POSTGRES_PORT: int
|
POSTGRES_PORT: int = 5432
|
||||||
POSTGRES_USER: str
|
POSTGRES_USER: str = "postgres"
|
||||||
POSTGRES_PASSWORD: str
|
POSTGRES_PASSWORD: str = "postgres"
|
||||||
POSTGRES_DB: str
|
POSTGRES_DB: str = "lawyer_ai"
|
||||||
|
|
||||||
QDRANT_HOST: str
|
QDRANT_HOST: str = "localhost"
|
||||||
QDRANT_PORT: int
|
QDRANT_PORT: int = 6333
|
||||||
|
|
||||||
REDIS_HOST: str
|
REDIS_HOST: str = "localhost"
|
||||||
REDIS_PORT: int
|
REDIS_PORT: int = 6379
|
||||||
|
|
||||||
TELEGRAM_BOT_TOKEN: Optional[str] = None
|
TELEGRAM_BOT_TOKEN: Optional[str] = None
|
||||||
YANDEX_OCR_API_KEY: Optional[str] = None
|
YANDEX_OCR_API_KEY: Optional[str] = None
|
||||||
@ -29,11 +30,12 @@ class Settings(BaseSettings):
|
|||||||
|
|
||||||
APP_NAME: str = "ИИ-юрист"
|
APP_NAME: str = "ИИ-юрист"
|
||||||
DEBUG: bool = False
|
DEBUG: bool = False
|
||||||
SECRET_KEY: str
|
SECRET_KEY: str = "your-secret-key-change-in-production"
|
||||||
CORS_ORIGINS: list[str] = ["*"]
|
CORS_ORIGINS: list[str] = ["*"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def database_url(self) -> str:
|
def database_url(self) -> str:
|
||||||
|
"""Вычисляемый URL подключения"""
|
||||||
return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
return f"postgresql://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
||||||
|
|
||||||
class Config:
|
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 fastapi import Request
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
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.database.base import AsyncSessionLocal
|
||||||
from src.infrastructure.repositories.postgresql.user_repository import PostgreSQLUserRepository
|
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):
|
class DatabaseProvider(Provider):
|
||||||
@provide(scope=Scope.REQUEST)
|
@provide(scope=Scope.REQUEST)
|
||||||
async def get_db(self) -> AsyncIterator[AsyncSession]:
|
@asynccontextmanager
|
||||||
|
async def get_db(self) -> AsyncSession:
|
||||||
async with AsyncSessionLocal() as session:
|
async with AsyncSessionLocal() as session:
|
||||||
try:
|
try:
|
||||||
yield session
|
yield session
|
||||||
@ -94,8 +95,6 @@ class ServiceProvider(Provider):
|
|||||||
def get_parser_service(self, ocr_service: YandexOCRService) -> DocumentParserService:
|
def get_parser_service(self, ocr_service: YandexOCRService) -> DocumentParserService:
|
||||||
return DocumentParserService(ocr_service)
|
return DocumentParserService(ocr_service)
|
||||||
|
|
||||||
|
|
||||||
class VectorServiceProvider(Provider):
|
|
||||||
@provide(scope=Scope.APP)
|
@provide(scope=Scope.APP)
|
||||||
def get_qdrant_client(self) -> QdrantClient:
|
def get_qdrant_client(self) -> QdrantClient:
|
||||||
return QdrantClient(host=settings.QDRANT_HOST, port=settings.QDRANT_PORT)
|
return QdrantClient(host=settings.QDRANT_HOST, port=settings.QDRANT_PORT)
|
||||||
@ -133,12 +132,6 @@ class VectorServiceProvider(Provider):
|
|||||||
splitter=text_splitter,
|
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):
|
class UseCaseProvider(Provider):
|
||||||
@provide(scope=Scope.REQUEST)
|
@provide(scope=Scope.REQUEST)
|
||||||
@ -196,12 +189,10 @@ class UseCaseProvider(Provider):
|
|||||||
|
|
||||||
|
|
||||||
def create_container() -> Container:
|
def create_container() -> Container:
|
||||||
container = Container()
|
return make_async_container(
|
||||||
container.add_provider(DatabaseProvider())
|
DatabaseProvider(),
|
||||||
container.add_provider(RepositoryProvider())
|
RepositoryProvider(),
|
||||||
container.add_provider(ServiceProvider())
|
ServiceProvider(),
|
||||||
container.add_provider(AuthProvider())
|
UseCaseProvider()
|
||||||
container.add_provider(UseCaseProvider())
|
)
|
||||||
container.add_provider(VectorServiceProvider())
|
|
||||||
return container
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user