Добавлены новые методы для получения статистики постов пользователей, информации о последних постах и количестве банов. Обновлены запросы в репозиториях для сортировки пользователей по дате бана. Исправлены вызовы функций форматирования сообщений для администраторов. Обновлены тесты для проверки новых функциональностей.
This commit is contained in:
@@ -4,7 +4,8 @@ HTTP клиент для взаимодействия с внешним RAG се
|
||||
Использует REST API для получения скоров и отправки примеров.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, Optional
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import httpx
|
||||
|
||||
@@ -15,6 +16,30 @@ from .base import ScoringResult
|
||||
from .exceptions import InsufficientExamplesError, ScoringError, TextTooShortError
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimilarPost:
|
||||
"""Данные о похожем посте."""
|
||||
|
||||
similarity: float
|
||||
created_at: int
|
||||
post_id: Optional[int]
|
||||
text: str
|
||||
rag_score: Optional[float]
|
||||
|
||||
|
||||
@dataclass
|
||||
class SimilarPostsResult:
|
||||
"""Результат поиска похожих постов."""
|
||||
|
||||
similar_count: int
|
||||
similar_posts: List[SimilarPost]
|
||||
max_similarity: float = 0.0
|
||||
|
||||
def __post_init__(self):
|
||||
if self.similar_posts:
|
||||
self.max_similarity = max(p.similarity for p in self.similar_posts)
|
||||
|
||||
|
||||
class RagApiClient:
|
||||
"""
|
||||
HTTP клиент для взаимодействия с внешним RAG сервисом.
|
||||
@@ -329,21 +354,39 @@ class RagApiClient:
|
||||
Словарь со статистикой или пустой словарь при ошибке
|
||||
"""
|
||||
if not self._enabled:
|
||||
logger.debug("RagApiClient: get_stats пропущен - клиент отключен")
|
||||
return {}
|
||||
|
||||
try:
|
||||
logger.debug(f"RagApiClient: Запрос статистики от {self.api_url}/stats")
|
||||
response = await self._client.get(f"{self.api_url}/stats")
|
||||
|
||||
if response.status_code == 200:
|
||||
return response.json()
|
||||
data = response.json()
|
||||
logger.info(
|
||||
f"RagApiClient: Статистика получена успешно: "
|
||||
f"model_loaded={data.get('model_loaded')}, "
|
||||
f"model_name={data.get('model_name')}, "
|
||||
f"vector_store={data.get('vector_store', {}).get('total_count', 'N/A')} примеров"
|
||||
)
|
||||
return data
|
||||
elif response.status_code == 401 or response.status_code == 403:
|
||||
logger.warning(
|
||||
f"RagApiClient: Ошибка авторизации при получении статистики: "
|
||||
f"status={response.status_code}, body={response.text[:200]}"
|
||||
)
|
||||
return {}
|
||||
else:
|
||||
logger.warning(
|
||||
f"RagApiClient: Неожиданный статус при получении статистики: {response.status_code}"
|
||||
f"RagApiClient: Неожиданный статус при получении статистики: "
|
||||
f"status={response.status_code}, body={response.text[:200]}"
|
||||
)
|
||||
return {}
|
||||
|
||||
except httpx.TimeoutException:
|
||||
logger.warning(f"RagApiClient: Таймаут при получении статистики")
|
||||
logger.warning(
|
||||
f"RagApiClient: Таймаут при получении статистики (timeout={self.timeout}s)"
|
||||
)
|
||||
return {}
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(
|
||||
@@ -365,3 +408,135 @@ class RagApiClient:
|
||||
"api_url": self.api_url,
|
||||
"timeout": self.timeout,
|
||||
}
|
||||
|
||||
@track_time("find_similar_posts", "rag_client")
|
||||
async def find_similar_posts(
|
||||
self, text: str, threshold: float = 0.9, hours: int = 24
|
||||
) -> Optional[SimilarPostsResult]:
|
||||
"""
|
||||
Ищет похожие посты за последние N часов.
|
||||
|
||||
Args:
|
||||
text: Текст поста для поиска похожих
|
||||
threshold: Порог схожести (0.0-1.0), по умолчанию 0.9
|
||||
hours: За сколько часов искать (1-168), по умолчанию 24
|
||||
|
||||
Returns:
|
||||
SimilarPostsResult с информацией о похожих постах или None при ошибке
|
||||
"""
|
||||
if not self._enabled:
|
||||
return None
|
||||
|
||||
if not text or not text.strip():
|
||||
return None
|
||||
|
||||
try:
|
||||
response = await self._client.post(
|
||||
f"{self.api_url}/similar",
|
||||
json={"text": text.strip(), "threshold": threshold, "hours": hours},
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
similar_posts = []
|
||||
|
||||
for post_data in data.get("similar_posts", []):
|
||||
similar_posts.append(
|
||||
SimilarPost(
|
||||
similarity=float(post_data.get("similarity", 0.0)),
|
||||
created_at=int(post_data.get("created_at", 0)),
|
||||
post_id=post_data.get("post_id"),
|
||||
text=post_data.get("text", ""),
|
||||
rag_score=post_data.get("rag_score"),
|
||||
)
|
||||
)
|
||||
|
||||
result = SimilarPostsResult(
|
||||
similar_count=data.get("similar_count", 0),
|
||||
similar_posts=similar_posts,
|
||||
)
|
||||
|
||||
if result.similar_count > 0:
|
||||
logger.info(
|
||||
f"RagApiClient: Найдено {result.similar_count} похожих постов "
|
||||
f"(max_similarity={result.max_similarity:.2%})"
|
||||
)
|
||||
|
||||
return result
|
||||
else:
|
||||
logger.warning(
|
||||
f"RagApiClient: Неожиданный статус при поиске похожих постов: "
|
||||
f"{response.status_code}, body: {response.text}"
|
||||
)
|
||||
return None
|
||||
|
||||
except httpx.TimeoutException:
|
||||
logger.warning("RagApiClient: Таймаут при поиске похожих постов")
|
||||
return None
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(
|
||||
f"RagApiClient: Ошибка подключения при поиске похожих постов: {e}"
|
||||
)
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"RagApiClient: Ошибка поиска похожих постов: {e}")
|
||||
return None
|
||||
|
||||
@track_time("add_submitted_post", "rag_client")
|
||||
async def add_submitted_post(
|
||||
self, text: str, post_id: Optional[int] = None, rag_score: Optional[float] = None
|
||||
) -> bool:
|
||||
"""
|
||||
Добавляет пост в коллекцию submitted для поиска похожих.
|
||||
|
||||
Args:
|
||||
text: Текст поста
|
||||
post_id: ID поста (опционально)
|
||||
rag_score: RAG скор на момент добавления (опционально)
|
||||
|
||||
Returns:
|
||||
True если пост успешно добавлен
|
||||
"""
|
||||
if not self._enabled:
|
||||
return False
|
||||
|
||||
if not text or not text.strip():
|
||||
return False
|
||||
|
||||
try:
|
||||
payload = {"text": text.strip()}
|
||||
if post_id is not None:
|
||||
payload["post_id"] = post_id
|
||||
if rag_score is not None:
|
||||
payload["rag_score"] = rag_score
|
||||
|
||||
response = await self._client.post(
|
||||
f"{self.api_url}/submitted",
|
||||
json=payload,
|
||||
)
|
||||
|
||||
if response.status_code in (200, 201):
|
||||
data = response.json()
|
||||
logger.debug(
|
||||
f"RagApiClient: Пост добавлен в submitted "
|
||||
f"(post_id={post_id}, submitted_count={data.get('submitted_count', 'N/A')})"
|
||||
)
|
||||
return True
|
||||
else:
|
||||
logger.warning(
|
||||
f"RagApiClient: Неожиданный статус при добавлении в submitted: "
|
||||
f"{response.status_code}"
|
||||
)
|
||||
return False
|
||||
|
||||
except httpx.TimeoutException:
|
||||
logger.warning("RagApiClient: Таймаут при добавлении в submitted")
|
||||
return False
|
||||
except httpx.RequestError as e:
|
||||
logger.warning(
|
||||
f"RagApiClient: Ошибка подключения при добавлении в submitted: {e}"
|
||||
)
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"RagApiClient: Ошибка добавления в submitted: {e}")
|
||||
return False
|
||||
|
||||
@@ -221,3 +221,43 @@ class ScoringManager:
|
||||
stats["deepseek"] = self.deepseek_service.get_stats()
|
||||
|
||||
return stats
|
||||
|
||||
@track_time("find_similar_posts", "scoring_manager")
|
||||
async def find_similar_posts(
|
||||
self, text: str, threshold: float = 0.9, hours: int = 24
|
||||
):
|
||||
"""
|
||||
Ищет похожие посты через RAG API.
|
||||
|
||||
Args:
|
||||
text: Текст для поиска похожих
|
||||
threshold: Порог схожести (0.0-1.0)
|
||||
hours: За сколько часов искать
|
||||
|
||||
Returns:
|
||||
SimilarPostsResult или None
|
||||
"""
|
||||
if not self.rag_client or not self.rag_client.is_enabled:
|
||||
return None
|
||||
|
||||
return await self.rag_client.find_similar_posts(text, threshold, hours)
|
||||
|
||||
@track_time("add_submitted_post", "scoring_manager")
|
||||
async def add_submitted_post(
|
||||
self, text: str, post_id: Optional[int] = None, rag_score: Optional[float] = None
|
||||
) -> bool:
|
||||
"""
|
||||
Добавляет пост в коллекцию submitted для поиска похожих.
|
||||
|
||||
Args:
|
||||
text: Текст поста
|
||||
post_id: ID поста (опционально)
|
||||
rag_score: RAG скор на момент добавления (опционально)
|
||||
|
||||
Returns:
|
||||
True если успешно добавлен
|
||||
"""
|
||||
if not self.rag_client or not self.rag_client.is_enabled:
|
||||
return False
|
||||
|
||||
return await self.rag_client.add_submitted_post(text, post_id, rag_score)
|
||||
|
||||
Reference in New Issue
Block a user