Spaces:
Sleeping
Sleeping
Aissugur Kurganbekov Claude Opus 4.8 commited on
Commit ·
03863fd
1
Parent(s): f65a6b3
Fix CI: make tests hermetic and harden hybrid_rank against attr-less chunks
Browse filesCI installs fastembed (requirements-dev -> requirements), which activated the
dense retrieval path during tests and surfaced two issues:
- hybrid_rank read chunk.embedding directly, crashing on the SimpleNamespace
test stand-ins (and any chunk-like object without the attribute). Use
getattr(c, embedding, None) so such a chunk simply stays lexical.
- The suite would download the ~130 MB embedding model on every run (slow and
flaky). conftest now disables embeddings, so tests are hermetic and
deterministic; the TF-IDF+vector fusion is already unit-tested with mocked
vectors in test_embeddings.py.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- backend/app/retrieval.py +3 -1
- backend/tests/conftest.py +7 -0
backend/app/retrieval.py
CHANGED
|
@@ -110,7 +110,9 @@ def hybrid_rank(
|
|
| 110 |
return tfidf_scored[:top_k]
|
| 111 |
|
| 112 |
# Semantic ranking over every chunk that has a stored vector (one matmul).
|
| 113 |
-
|
|
|
|
|
|
|
| 114 |
pairs = [(c, v) for c, v in pairs if v is not None and v.shape == qvec.shape]
|
| 115 |
if not pairs:
|
| 116 |
return tfidf_scored[:top_k]
|
|
|
|
| 110 |
return tfidf_scored[:top_k]
|
| 111 |
|
| 112 |
# Semantic ranking over every chunk that has a stored vector (one matmul).
|
| 113 |
+
# getattr keeps this robust to any chunk-like object without an embedding
|
| 114 |
+
# attribute — such a chunk simply contributes no vector and stays lexical.
|
| 115 |
+
pairs = [(c, embeddings.to_vector(getattr(c, "embedding", None))) for c in chunks]
|
| 116 |
pairs = [(c, v) for c, v in pairs if v is not None and v.shape == qvec.shape]
|
| 117 |
if not pairs:
|
| 118 |
return tfidf_scored[:top_k]
|
backend/tests/conftest.py
CHANGED
|
@@ -14,9 +14,16 @@ from fastapi.testclient import TestClient
|
|
| 14 |
from sqlalchemy import create_engine
|
| 15 |
from sqlalchemy.orm import sessionmaker
|
| 16 |
|
|
|
|
| 17 |
from app.database import Base, get_db
|
| 18 |
from app.main import app
|
| 19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
@pytest.fixture()
|
| 22 |
def _engine():
|
|
|
|
| 14 |
from sqlalchemy import create_engine
|
| 15 |
from sqlalchemy.orm import sessionmaker
|
| 16 |
|
| 17 |
+
from app import config
|
| 18 |
from app.database import Base, get_db
|
| 19 |
from app.main import app
|
| 20 |
|
| 21 |
+
# Keep the suite hermetic and deterministic: the optional dense-embedding model
|
| 22 |
+
# (fastembed) is a ~130 MB network download that would make CI slow and flaky, so
|
| 23 |
+
# tests run on pure TF-IDF. The hybrid TF-IDF+vector fusion itself is covered
|
| 24 |
+
# deterministically with mocked vectors in test_embeddings.py.
|
| 25 |
+
config.EMBED_ENABLED = False
|
| 26 |
+
|
| 27 |
|
| 28 |
@pytest.fixture()
|
| 29 |
def _engine():
|