model-path-fix
Some checks failed
Deploy on push / deploy (push) Failing after 1m14s

This commit is contained in:
2025-09-01 16:10:10 +03:00
parent a1e4d0d391
commit 9daade05c0
6 changed files with 103 additions and 53 deletions

View File

@@ -9,11 +9,12 @@ from typing import Any, Dict, List
import muvera
import numpy as np
from sentence_transformers import SentenceTransformer
from settings import MUVERA_INDEX_NAME, SEARCH_MAX_BATCH_SIZE, SEARCH_PREFETCH_SIZE
from utils.logger import root_logger as logger
# Отложенный импорт SentenceTransformer для избежания блокировки запуска
SentenceTransformer = None
primary_model = "paraphrase-multilingual-MiniLM-L12-v2"
@@ -22,7 +23,9 @@ def get_models_cache_dir() -> str:
"""Определяет лучшую папку для кеша моделей"""
# Пробуем /dump если доступен для записи
dump_path = Path("/dump")
logger.info(f"🔍 Checking /dump - exists: {dump_path.exists()}, writable: {os.access('/dump', os.W_OK) if dump_path.exists() else 'N/A'}")
logger.info(
f"🔍 Checking /dump - exists: {dump_path.exists()}, writable: {os.access('/dump', os.W_OK) if dump_path.exists() else 'N/A'}"
)
if dump_path.exists() and os.access("/dump", os.W_OK):
cache_dir = "/dump/huggingface"
@@ -41,13 +44,28 @@ def get_models_cache_dir() -> str:
MODELS_CACHE_DIR = get_models_cache_dir()
os.environ.setdefault("TRANSFORMERS_CACHE", MODELS_CACHE_DIR)
# Используем HF_HOME вместо устаревшего TRANSFORMERS_CACHE
os.environ.setdefault("HF_HOME", MODELS_CACHE_DIR)
# Global collection for background tasks
background_tasks: List[asyncio.Task] = []
def _lazy_import_sentence_transformers():
"""🔄 Lazy import SentenceTransformer для избежания блокировки старта приложения"""
global SentenceTransformer # noqa: PLW0603
if SentenceTransformer is None:
try:
from sentence_transformers import SentenceTransformer as SentenceTransformerClass
SentenceTransformer = SentenceTransformerClass
logger.info("✅ SentenceTransformer импортирован успешно")
except ImportError as e:
logger.error(f"Не удалось импортировать SentenceTransformer: {e}")
SentenceTransformer = None
return SentenceTransformer
class MuveraWrapper:
"""🔍 Real vector search with SentenceTransformers + FDE encoding"""
@@ -60,42 +78,10 @@ class MuveraWrapper:
self.documents: Dict[str, Dict[str, Any]] = {} # Simple in-memory storage for demo
self.embeddings: Dict[str, np.ndarray | None] = {} # Store encoded embeddings
# 🚀 Инициализируем реальную модель эмбедингов с локальным кешом
try:
logger.info(f"💾 Using models cache directory: {MODELS_CACHE_DIR}")
# Проверяем наличие основной модели
is_cached = self._is_model_cached(primary_model)
if is_cached:
logger.info(f"🔍 Found cached model: {primary_model}")
else:
logger.info(f"🔽 Downloading model: {primary_model}")
# Используем многоязычную модель, хорошо работающую с русским
self.encoder = SentenceTransformer(
primary_model,
cache_folder=MODELS_CACHE_DIR,
local_files_only=is_cached, # Не скачиваем если уже есть в кеше
)
logger.info("🔍 SentenceTransformer model loaded successfully")
except Exception as e:
logger.error(f"Failed to load primary SentenceTransformer: {e}")
# Fallback - простая модель
try:
fallback_model = "all-MiniLM-L6-v2"
is_fallback_cached = self._is_model_cached(fallback_model)
if is_fallback_cached:
logger.info(f"🔍 Found cached fallback model: {fallback_model}")
else:
logger.info(f"🔽 Downloading fallback model: {fallback_model}")
self.encoder = SentenceTransformer(
fallback_model, cache_folder=MODELS_CACHE_DIR, local_files_only=is_fallback_cached
)
logger.info("🔍 Fallback SentenceTransformer model loaded")
except Exception:
logger.error("Failed to load any SentenceTransformer model")
self.encoder = None
# 🚀 Откладываем инициализацию модели до первого использования
logger.info("🔄 MuveraWrapper инициализирован - модель будет загружена при первом использовании")
self.encoder = None
self._model_loaded = False
def _is_model_cached(self, model_name: str) -> bool:
"""🔍 Проверяет наличие модели в кеше"""
@@ -128,6 +114,60 @@ class MuveraWrapper:
logger.debug(f"Error checking model cache for {model_name}: {e}")
return False
def _ensure_model_loaded(self) -> bool:
"""🔄 Убеждаемся что модель загружена (lazy loading)"""
if self._model_loaded:
return self.encoder is not None
# Импортируем SentenceTransformer при первой необходимости
sentence_transformer_class = _lazy_import_sentence_transformers()
if sentence_transformer_class is None:
logger.error("❌ SentenceTransformer недоступен")
return False
try:
logger.info(f"💾 Using models cache directory: {MODELS_CACHE_DIR}")
# Проверяем наличие основной модели
is_cached = self._is_model_cached(primary_model)
if is_cached:
logger.info(f"🔍 Found cached model: {primary_model}")
else:
logger.info(f"🔽 Downloading model: {primary_model}")
# Используем многоязычную модель, хорошо работающую с русским
self.encoder = sentence_transformer_class(
primary_model,
cache_folder=MODELS_CACHE_DIR,
local_files_only=is_cached, # Не скачиваем если уже есть в кеше
)
logger.info("🔍 SentenceTransformer model loaded successfully")
self._model_loaded = True
return True
except Exception as e:
logger.error(f"Failed to load primary SentenceTransformer: {e}")
# Fallback - простая модель
try:
fallback_model = "all-MiniLM-L6-v2"
is_fallback_cached = self._is_model_cached(fallback_model)
if is_fallback_cached:
logger.info(f"🔍 Found cached fallback model: {fallback_model}")
else:
logger.info(f"🔽 Downloading fallback model: {fallback_model}")
self.encoder = sentence_transformer_class(
fallback_model, cache_folder=MODELS_CACHE_DIR, local_files_only=is_fallback_cached
)
logger.info("🔍 Fallback SentenceTransformer model loaded")
self._model_loaded = True
return True
except Exception:
logger.error("Failed to load any SentenceTransformer model")
self.encoder = None
self._model_loaded = True # Помечаем как попытка завершена
return False
async def async_init(self) -> None:
"""🔄 Асинхронная инициализация - восстановление индекса из файла"""
try:
@@ -153,7 +193,12 @@ class MuveraWrapper:
async def search(self, query: str, limit: int) -> List[Dict[str, Any]]:
"""🔍 Real vector search using SentenceTransformers + FDE encoding"""
if not query.strip() or not self.encoder:
if not query.strip():
return []
# Загружаем модель при первом использовании
if not self._ensure_model_loaded():
logger.warning("🔍 Search unavailable - model not loaded")
return []
try:
@@ -194,7 +239,8 @@ class MuveraWrapper:
async def index(self, documents: List[Dict[str, Any]], silent: bool = False) -> None:
"""🚀 Index documents using real SentenceTransformers + FDE encoding"""
if not self.encoder:
# Загружаем модель при первом использовании
if not self._ensure_model_loaded():
if not silent:
logger.warning("🔍 No encoder available for indexing")
return