feat: интеграция ML-скоринга с использованием RAG и DeepSeek
- Обновлен Dockerfile для установки необходимых зависимостей. - Добавлены новые переменные окружения для настройки ML-скоринга в env.example. - Реализованы методы для получения и обновления ML-скоров в AsyncBotDB и PostRepository. - Обновлены обработчики публикации постов для интеграции ML-скоринга. - Добавлен новый обработчик для получения статистики ML-скоринга в админ-панели. - Обновлены функции для форматирования сообщений с учетом ML-скоров.
This commit is contained in:
@@ -5,6 +5,7 @@ from typing import Optional
|
||||
from database.async_db import AsyncBotDB
|
||||
from dotenv import load_dotenv
|
||||
from helper_bot.utils.s3_storage import S3StorageService
|
||||
from logs.custom_logger import logger
|
||||
|
||||
|
||||
class BaseDependencyFactory:
|
||||
@@ -15,6 +16,7 @@ class BaseDependencyFactory:
|
||||
load_dotenv(env_path)
|
||||
|
||||
self.settings = {}
|
||||
self._project_dir = project_dir
|
||||
|
||||
database_path = os.getenv('DATABASE_PATH', 'database/tg-bot-database.db')
|
||||
if not os.path.isabs(database_path):
|
||||
@@ -24,6 +26,9 @@ class BaseDependencyFactory:
|
||||
|
||||
self._load_settings_from_env()
|
||||
self._init_s3_storage()
|
||||
|
||||
# ScoringManager инициализируется лениво
|
||||
self._scoring_manager = None
|
||||
|
||||
def _load_settings_from_env(self):
|
||||
"""Загружает настройки из переменных окружения."""
|
||||
@@ -59,6 +64,23 @@ class BaseDependencyFactory:
|
||||
'bucket_name': os.getenv('S3_BUCKET_NAME', ''),
|
||||
'region': os.getenv('S3_REGION', 'us-east-1')
|
||||
}
|
||||
|
||||
# Настройки ML-скоринга
|
||||
self.settings['Scoring'] = {
|
||||
# RAG (ruBERT)
|
||||
'rag_enabled': self._parse_bool(os.getenv('RAG_ENABLED', 'false')),
|
||||
'rag_model': os.getenv('RAG_MODEL', 'DeepPavlov/rubert-base-cased'),
|
||||
'rag_cache_dir': os.getenv('RAG_CACHE_DIR', 'data/models'),
|
||||
'rag_vectors_path': os.getenv('RAG_VECTORS_PATH', 'data/vectors.npz'),
|
||||
'rag_max_examples': self._parse_int(os.getenv('RAG_MAX_EXAMPLES', '10000')),
|
||||
'rag_score_multiplier': self._parse_float(os.getenv('RAG_SCORE_MULTIPLIER', '5.0')),
|
||||
# DeepSeek
|
||||
'deepseek_enabled': self._parse_bool(os.getenv('DEEPSEEK_ENABLED', 'false')),
|
||||
'deepseek_api_key': os.getenv('DEEPSEEK_API_KEY', ''),
|
||||
'deepseek_api_url': os.getenv('DEEPSEEK_API_URL', 'https://api.deepseek.com/v1/chat/completions'),
|
||||
'deepseek_model': os.getenv('DEEPSEEK_MODEL', 'deepseek-chat'),
|
||||
'deepseek_timeout': self._parse_int(os.getenv('DEEPSEEK_TIMEOUT', '30')),
|
||||
}
|
||||
|
||||
def _init_s3_storage(self):
|
||||
"""Инициализирует S3StorageService если S3 включен."""
|
||||
@@ -84,6 +106,13 @@ class BaseDependencyFactory:
|
||||
return int(value)
|
||||
except (ValueError, TypeError):
|
||||
return 0
|
||||
|
||||
def _parse_float(self, value: str) -> float:
|
||||
"""Парсит строковое значение в float."""
|
||||
try:
|
||||
return float(value)
|
||||
except (ValueError, TypeError):
|
||||
return 0.0
|
||||
|
||||
def get_settings(self):
|
||||
return self.settings
|
||||
@@ -95,6 +124,100 @@ class BaseDependencyFactory:
|
||||
def get_s3_storage(self) -> Optional[S3StorageService]:
|
||||
"""Возвращает S3StorageService если S3 включен, иначе None."""
|
||||
return self.s3_storage
|
||||
|
||||
def _init_scoring_manager(self):
|
||||
"""
|
||||
Инициализирует ScoringManager с RAG и DeepSeek сервисами.
|
||||
|
||||
Вызывается лениво при первом обращении к get_scoring_manager().
|
||||
"""
|
||||
from helper_bot.services.scoring import (
|
||||
ScoringManager,
|
||||
RAGService,
|
||||
DeepSeekService,
|
||||
VectorStore,
|
||||
)
|
||||
|
||||
scoring_config = self.settings['Scoring']
|
||||
|
||||
# Инициализация RAG сервиса
|
||||
rag_service = None
|
||||
if scoring_config['rag_enabled']:
|
||||
# Путь к векторам
|
||||
vectors_path = scoring_config['rag_vectors_path']
|
||||
if not os.path.isabs(vectors_path):
|
||||
vectors_path = os.path.join(self._project_dir, vectors_path)
|
||||
|
||||
# Путь к кешу моделей
|
||||
cache_dir = scoring_config['rag_cache_dir']
|
||||
if not os.path.isabs(cache_dir):
|
||||
cache_dir = os.path.join(self._project_dir, cache_dir)
|
||||
|
||||
# Создаем директории если нужно
|
||||
os.makedirs(os.path.dirname(vectors_path), exist_ok=True)
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
|
||||
# Создаем VectorStore
|
||||
vector_store = VectorStore(
|
||||
vector_dim=768, # ruBERT dimension
|
||||
max_examples=scoring_config['rag_max_examples'],
|
||||
storage_path=vectors_path,
|
||||
score_multiplier=scoring_config['rag_score_multiplier'],
|
||||
)
|
||||
|
||||
# Создаем RAGService
|
||||
rag_service = RAGService(
|
||||
model_name=scoring_config['rag_model'],
|
||||
vector_store=vector_store,
|
||||
cache_dir=cache_dir,
|
||||
enabled=True,
|
||||
)
|
||||
|
||||
logger.info(f"RAGService инициализирован: {scoring_config['rag_model']}")
|
||||
|
||||
# Инициализация DeepSeek сервиса
|
||||
deepseek_service = None
|
||||
if scoring_config['deepseek_enabled'] and scoring_config['deepseek_api_key']:
|
||||
deepseek_service = DeepSeekService(
|
||||
api_key=scoring_config['deepseek_api_key'],
|
||||
api_url=scoring_config['deepseek_api_url'],
|
||||
model=scoring_config['deepseek_model'],
|
||||
timeout=scoring_config['deepseek_timeout'],
|
||||
enabled=True,
|
||||
)
|
||||
logger.info(f"DeepSeekService инициализирован: {scoring_config['deepseek_model']}")
|
||||
|
||||
# Создаем менеджер
|
||||
self._scoring_manager = ScoringManager(
|
||||
rag_service=rag_service,
|
||||
deepseek_service=deepseek_service,
|
||||
)
|
||||
|
||||
return self._scoring_manager
|
||||
|
||||
def get_scoring_manager(self):
|
||||
"""
|
||||
Возвращает ScoringManager для ML-скоринга постов.
|
||||
|
||||
Инициализируется лениво при первом вызове.
|
||||
|
||||
Returns:
|
||||
ScoringManager или None если скоринг полностью отключен
|
||||
"""
|
||||
if self._scoring_manager is None:
|
||||
scoring_config = self.settings.get('Scoring', {})
|
||||
|
||||
# Проверяем, включен ли хотя бы один сервис
|
||||
rag_enabled = scoring_config.get('rag_enabled', False)
|
||||
deepseek_enabled = scoring_config.get('deepseek_enabled', False)
|
||||
|
||||
if not rag_enabled and not deepseek_enabled:
|
||||
logger.info("Scoring полностью отключен (RAG и DeepSeek disabled)")
|
||||
return None
|
||||
|
||||
self._init_scoring_manager()
|
||||
|
||||
return self._scoring_manager
|
||||
|
||||
|
||||
_global_instance = None
|
||||
|
||||
Reference in New Issue
Block a user