brief-rags-bench/app/api/v1/query.py

203 lines
7.1 KiB
Python
Raw Normal View History

2025-12-17 15:37:32 +01:00
"""
Query API endpoints.
Отправка запросов к RAG backends в двух режимах:
1. Bench mode - batch запросы
2. Backend mode - последовательные запросы
"""
from fastapi import APIRouter, Depends, HTTPException, status
from typing import Dict, Any
from app.models.query import BenchQueryRequest, BackendQueryRequest, QueryResponse
from app.interfaces.db_api_client import DBApiClient
from app.services.rag_service import RagService
from app.dependencies import get_db_client, get_current_user
import httpx
import logging
from datetime import datetime
import uuid
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/query", tags=["query"])
def get_rag_service() -> RagService:
"""Dependency для получения RAG service."""
return RagService()
@router.post("/bench", response_model=QueryResponse)
async def bench_query(
request: BenchQueryRequest,
current_user: dict = Depends(get_current_user),
db_client: DBApiClient = Depends(get_db_client),
rag_service: RagService = Depends(get_rag_service)
):
"""
Отправить batch запрос к RAG backend (bench mode).
Отправляет все вопросы одним запросом.
Args:
request: Запрос с окружением и списком вопросов
Returns:
QueryResponse: Ответ от RAG backend с metadata
"""
user_id = current_user["user_id"]
environment = request.environment.lower()
# Валидация окружения
if environment not in ['ift', 'psi', 'prod']:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid environment. Must be one of: ift, psi, prod"
)
try:
# Получить настройки пользователя из DB API
user_settings_response = await db_client.get_user_settings(user_id)
env_settings = user_settings_response.settings.get(environment)
if not env_settings:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Settings not found for environment: {environment}"
)
# Проверить что apiMode = bench
if env_settings.apiMode != 'bench':
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Environment {environment} is not configured for bench mode"
)
# Сгенерировать request_id
request_id = str(uuid.uuid4())
logger.info(
f"User {user_id} sending bench query to {environment}: "
f"{len(request.questions)} questions, request_id={request_id}"
)
# Отправить запрос к RAG backend
env_settings_dict = env_settings.model_dump()
response_data = await rag_service.send_bench_query(
environment=environment,
questions=request.questions,
user_settings=env_settings_dict,
request_id=request_id
)
# Формируем ответ
return QueryResponse(
request_id=request_id,
timestamp=datetime.utcnow().isoformat() + "Z",
environment=environment,
response=response_data
)
except httpx.HTTPStatusError as e:
logger.error(f"RAG backend error for bench query: {e}")
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=f"RAG backend returned error: {e.response.status_code}"
)
except Exception as e:
logger.error(f"Unexpected error in bench query: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal server error"
)
finally:
await rag_service.close()
@router.post("/backend", response_model=QueryResponse)
async def backend_query(
request: BackendQueryRequest,
current_user: dict = Depends(get_current_user),
db_client: DBApiClient = Depends(get_db_client),
rag_service: RagService = Depends(get_rag_service)
):
"""
Отправить запросы к RAG backend (backend mode).
Отправляет вопросы по одному с возможностью сброса сессии.
Args:
request: Запрос с окружением, вопросами и флагом reset_session
Returns:
QueryResponse: Список ответов от RAG backend с metadata
"""
user_id = current_user["user_id"]
environment = request.environment.lower()
# Валидация окружения
if environment not in ['ift', 'psi', 'prod']:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid environment. Must be one of: ift, psi, prod"
)
try:
# Получить настройки пользователя из DB API
user_settings_response = await db_client.get_user_settings(user_id)
env_settings = user_settings_response.settings.get(environment)
if not env_settings:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Settings not found for environment: {environment}"
)
# Проверить что apiMode = backend
if env_settings.apiMode != 'backend':
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Environment {environment} is not configured for backend mode"
)
# Сгенерировать request_id
request_id = str(uuid.uuid4())
logger.info(
f"User {user_id} sending backend query to {environment}: "
f"{len(request.questions)} questions, request_id={request_id}, "
f"reset_session={request.reset_session}"
)
# Отправить запросы к RAG backend
env_settings_dict = env_settings.model_dump()
response_data = await rag_service.send_backend_query(
environment=environment,
questions=request.questions,
user_settings=env_settings_dict,
reset_session=request.reset_session
)
# Формируем ответ
return QueryResponse(
request_id=request_id,
timestamp=datetime.utcnow().isoformat() + "Z",
environment=environment,
response={"answers": response_data} # Оборачиваем в объект
)
except httpx.HTTPStatusError as e:
logger.error(f"RAG backend error for backend query: {e}")
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=f"RAG backend returned error: {e.response.status_code}"
)
except Exception as e:
logger.error(f"Unexpected error in backend query: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Internal server error"
)
finally:
await rag_service.close()