Spaces:
Sleeping
Sleeping
| """BM25-style sparse vectors via fastembed, used for the lexical branch of | |
| hybrid retrieval. Qdrant fuses the dense and sparse branches with RRF.""" | |
| import logging | |
| import time | |
| from threading import Lock | |
| log = logging.getLogger("mmap.sparse") | |
| SPARSE_MODEL_NAME = "Qdrant/bm25" | |
| SPARSE_VECTOR_NAME = "bm25" | |
| _model_lock = Lock() | |
| _model = None | |
| def get_sparse_model(): | |
| global _model | |
| if _model is None: | |
| with _model_lock: | |
| if _model is None: | |
| from fastembed import SparseTextEmbedding # type: ignore[import-not-found] | |
| last: Exception | None = None | |
| for attempt in range(1, 6): | |
| try: | |
| _model = SparseTextEmbedding(model_name=SPARSE_MODEL_NAME) | |
| break | |
| except Exception as exc: # noqa: BLE001 | |
| last = exc | |
| if attempt == 5: | |
| break | |
| backoff = attempt * 5 | |
| log.warning( | |
| "sparse model load failed (attempt %d/5): %s — retry in %ds", | |
| attempt, | |
| exc, | |
| backoff, | |
| ) | |
| time.sleep(backoff) | |
| if _model is None: | |
| raise RuntimeError( | |
| f"could not load sparse model after 5 attempts: {last}" | |
| ) from last | |
| return _model | |
| def encode_passages(texts: list[str]) -> list[tuple[list[int], list[float]]]: | |
| """Encode chunk texts as (indices, values) pairs suitable for | |
| qdrant_client.models.SparseVector. Order matches input.""" | |
| if not texts: | |
| return [] | |
| out: list[tuple[list[int], list[float]]] = [] | |
| for emb in get_sparse_model().embed(texts): | |
| out.append( | |
| ( | |
| [int(i) for i in emb.indices.tolist()], | |
| [float(v) for v in emb.values.tolist()], | |
| ) | |
| ) | |
| return out | |
| def encode_query(text: str) -> tuple[list[int], list[float]]: | |
| """Encode a query string with the query-side tokenizer.""" | |
| embs = list(get_sparse_model().query_embed([text])) | |
| if not embs: | |
| return [], [] | |
| emb = embs[0] | |
| return ( | |
| [int(i) for i in emb.indices.tolist()], | |
| [float(v) for v in emb.values.tolist()], | |
| ) | |