Davidtran99
commited on
Commit
·
c509ba7
1
Parent(s):
baaca6b
Fix: Sửa lỗi syntax embeddings + reranker trong bản Docker backend
Browse files
backend/hue_portal/core/embeddings.py
CHANGED
|
@@ -70,27 +70,27 @@ class EmbeddingModelManager:
|
|
| 70 |
model_name: Optional[str] = None,
|
| 71 |
force_reload: bool = False,
|
| 72 |
) -> Optional[SentenceTransformer]:
|
| 73 |
-
|
| 74 |
Get or load embedding model instance with thread-safe caching.
|
| 75 |
-
|
| 76 |
-
|
| 77 |
model_name: Name of the model to load.
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
print(
|
| 85 |
"Warning: sentence-transformers not installed. "
|
| 86 |
"Install with: pip install sentence-transformers"
|
| 87 |
)
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
if (
|
| 95 |
not force_reload
|
| 96 |
and self._model is not None
|
|
@@ -110,40 +110,40 @@ class EmbeddingModelManager:
|
|
| 110 |
|
| 111 |
def _load_model(self, resolved_model_name: str) -> Optional[SentenceTransformer]:
|
| 112 |
"""Internal method to load model (must be called with lock held)."""
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
self._model = SentenceTransformer(str(model_path))
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
self._model = SentenceTransformer(resolved_model_name, **model_kwargs)
|
| 127 |
|
| 128 |
self._model_name = resolved_model_name
|
| 129 |
-
|
| 130 |
-
|
| 131 |
test_embedding = self._model.encode("test", show_progress_bar=False)
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
|
| 137 |
return self._model
|
| 138 |
except Exception as exc:
|
| 139 |
print(f"❌ Error loading model {resolved_model_name}: {exc}")
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
self._model = SentenceTransformer(FALLBACK_MODEL_NAME)
|
| 144 |
self._model_name = FALLBACK_MODEL_NAME
|
| 145 |
test_embedding = self._model.encode("test", show_progress_bar=False)
|
| 146 |
-
|
| 147 |
print(
|
| 148 |
f"✅ Successfully loaded fallback model: {FALLBACK_MODEL_NAME} "
|
| 149 |
f"(dimension: {dim})"
|
|
|
|
| 70 |
model_name: Optional[str] = None,
|
| 71 |
force_reload: bool = False,
|
| 72 |
) -> Optional[SentenceTransformer]:
|
| 73 |
+
"""
|
| 74 |
Get or load embedding model instance with thread-safe caching.
|
| 75 |
+
|
| 76 |
+
Args:
|
| 77 |
model_name: Name of the model to load.
|
| 78 |
+
force_reload: Force reload model even if cached.
|
| 79 |
+
|
| 80 |
+
Returns:
|
| 81 |
+
SentenceTransformer instance or None if not available.
|
| 82 |
+
"""
|
| 83 |
+
if not SENTENCE_TRANSFORMERS_AVAILABLE:
|
| 84 |
print(
|
| 85 |
"Warning: sentence-transformers not installed. "
|
| 86 |
"Install with: pip install sentence-transformers"
|
| 87 |
)
|
| 88 |
+
return None
|
| 89 |
+
|
| 90 |
+
resolved_model_name = model_name or DEFAULT_MODEL_NAME
|
| 91 |
+
if resolved_model_name in AVAILABLE_MODELS:
|
| 92 |
+
resolved_model_name = AVAILABLE_MODELS[resolved_model_name]
|
| 93 |
+
|
| 94 |
if (
|
| 95 |
not force_reload
|
| 96 |
and self._model is not None
|
|
|
|
| 110 |
|
| 111 |
def _load_model(self, resolved_model_name: str) -> Optional[SentenceTransformer]:
|
| 112 |
"""Internal method to load model (must be called with lock held)."""
|
| 113 |
+
try:
|
| 114 |
+
print(f"Loading embedding model: {resolved_model_name}")
|
| 115 |
+
|
| 116 |
+
model_path = Path(resolved_model_name)
|
| 117 |
+
if model_path.exists() and model_path.is_dir():
|
| 118 |
+
print(f"Loading local model from: {resolved_model_name}")
|
| 119 |
self._model = SentenceTransformer(str(model_path))
|
| 120 |
+
else:
|
| 121 |
+
hf_token = os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_TOKEN")
|
| 122 |
+
model_kwargs = {}
|
| 123 |
+
if hf_token:
|
| 124 |
+
print(f"Using Hugging Face token for model: {resolved_model_name}")
|
| 125 |
+
model_kwargs["token"] = hf_token
|
| 126 |
self._model = SentenceTransformer(resolved_model_name, **model_kwargs)
|
| 127 |
|
| 128 |
self._model_name = resolved_model_name
|
| 129 |
+
|
| 130 |
+
try:
|
| 131 |
test_embedding = self._model.encode("test", show_progress_bar=False)
|
| 132 |
+
dim = len(test_embedding)
|
| 133 |
+
print(f"✅ Successfully loaded model: {resolved_model_name} (dimension: {dim})")
|
| 134 |
+
except Exception:
|
| 135 |
+
print(f"✅ Successfully loaded model: {resolved_model_name}")
|
| 136 |
|
| 137 |
return self._model
|
| 138 |
except Exception as exc:
|
| 139 |
print(f"❌ Error loading model {resolved_model_name}: {exc}")
|
| 140 |
+
if resolved_model_name != FALLBACK_MODEL_NAME:
|
| 141 |
+
print(f"Trying fallback model: {FALLBACK_MODEL_NAME}")
|
| 142 |
+
try:
|
| 143 |
self._model = SentenceTransformer(FALLBACK_MODEL_NAME)
|
| 144 |
self._model_name = FALLBACK_MODEL_NAME
|
| 145 |
test_embedding = self._model.encode("test", show_progress_bar=False)
|
| 146 |
+
dim = len(test_embedding)
|
| 147 |
print(
|
| 148 |
f"✅ Successfully loaded fallback model: {FALLBACK_MODEL_NAME} "
|
| 149 |
f"(dimension: {dim})"
|
backend/hue_portal/core/reranker.py
CHANGED
|
@@ -149,19 +149,19 @@ def rerank_documents(
|
|
| 149 |
# Rerank using cross-encoder
|
| 150 |
print(f"[RERANKER] Reranking {len(pairs)} documents...", flush=True)
|
| 151 |
logger.debug("[RERANKER] Reranking %d documents", len(pairs))
|
| 152 |
-
|
| 153 |
# Handle different reranker types
|
| 154 |
from FlagEmbedding import FlagReranker
|
| 155 |
from sentence_transformers import CrossEncoder
|
| 156 |
-
|
| 157 |
if isinstance(reranker, FlagReranker):
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
scored_docs = list(zip(doc_objects, scores))
|
| 166 |
else:
|
| 167 |
logger.warning("[RERANKER] Unexpected score type: %s", type(scores))
|
|
@@ -169,7 +169,7 @@ def rerank_documents(
|
|
| 169 |
elif isinstance(reranker, CrossEncoder):
|
| 170 |
# CrossEncoder.predict returns numpy array
|
| 171 |
scores = reranker.predict(pairs)
|
| 172 |
-
if hasattr(scores,
|
| 173 |
scores = scores.tolist()
|
| 174 |
elif not isinstance(scores, list):
|
| 175 |
scores = [float(scores)] if len(pairs) == 1 else list(scores)
|
|
|
|
| 149 |
# Rerank using cross-encoder
|
| 150 |
print(f"[RERANKER] Reranking {len(pairs)} documents...", flush=True)
|
| 151 |
logger.debug("[RERANKER] Reranking %d documents", len(pairs))
|
| 152 |
+
|
| 153 |
# Handle different reranker types
|
| 154 |
from FlagEmbedding import FlagReranker
|
| 155 |
from sentence_transformers import CrossEncoder
|
| 156 |
+
|
| 157 |
if isinstance(reranker, FlagReranker):
|
| 158 |
+
# FlagReranker.compute_score returns list of scores for multiple pairs
|
| 159 |
+
scores = reranker.compute_score(pairs, normalize=True)
|
| 160 |
+
|
| 161 |
+
# Handle both single score (float) and list of scores
|
| 162 |
+
if isinstance(scores, (int, float)):
|
| 163 |
+
scored_docs = [(doc_objects[0], float(scores))]
|
| 164 |
+
elif isinstance(scores, list):
|
| 165 |
scored_docs = list(zip(doc_objects, scores))
|
| 166 |
else:
|
| 167 |
logger.warning("[RERANKER] Unexpected score type: %s", type(scores))
|
|
|
|
| 169 |
elif isinstance(reranker, CrossEncoder):
|
| 170 |
# CrossEncoder.predict returns numpy array
|
| 171 |
scores = reranker.predict(pairs)
|
| 172 |
+
if hasattr(scores, "tolist"):
|
| 173 |
scores = scores.tolist()
|
| 174 |
elif not isinstance(scores, list):
|
| 175 |
scores = [float(scores)] if len(pairs) == 1 else list(scores)
|