Spaces:
Sleeping
Sleeping
Upload src/labdaps/retrieval/retriever.py with huggingface_hub
Browse files
src/labdaps/retrieval/retriever.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
import numpy as np
|
| 3 |
+
from src.labdaps.config import TOP_K_CANDIDATES, TOP_K_FINAL
|
| 4 |
+
from src.labdaps.retrieval.vector_store import query_store
|
| 5 |
+
from src.labdaps.ingestion.embedder import Embedder
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
@dataclass
|
| 9 |
+
class RetrievedChunk:
|
| 10 |
+
text: str
|
| 11 |
+
source_file: str
|
| 12 |
+
page_number: int
|
| 13 |
+
score: float
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def _cosine_similarity(a: list[float], b: list[float]) -> float:
|
| 17 |
+
a, b = np.array(a), np.array(b)
|
| 18 |
+
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-9))
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def _mmr(
|
| 22 |
+
query_embedding: list[float],
|
| 23 |
+
candidate_embeddings: list[list[float]],
|
| 24 |
+
candidates: list[dict],
|
| 25 |
+
top_k: int,
|
| 26 |
+
lambda_param: float = 0.6,
|
| 27 |
+
) -> list[int]:
|
| 28 |
+
selected = []
|
| 29 |
+
remaining = list(range(len(candidates)))
|
| 30 |
+
query_sims = [_cosine_similarity(query_embedding, e) for e in candidate_embeddings]
|
| 31 |
+
|
| 32 |
+
while len(selected) < top_k and remaining:
|
| 33 |
+
if not selected:
|
| 34 |
+
best = max(remaining, key=lambda i: query_sims[i])
|
| 35 |
+
else:
|
| 36 |
+
selected_embeddings = [candidate_embeddings[i] for i in selected]
|
| 37 |
+
best = max(
|
| 38 |
+
remaining,
|
| 39 |
+
key=lambda i: lambda_param * query_sims[i]
|
| 40 |
+
- (1 - lambda_param) * max(
|
| 41 |
+
_cosine_similarity(candidate_embeddings[i], se)
|
| 42 |
+
for se in selected_embeddings
|
| 43 |
+
),
|
| 44 |
+
)
|
| 45 |
+
selected.append(best)
|
| 46 |
+
remaining.remove(best)
|
| 47 |
+
|
| 48 |
+
return selected
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
def retrieve(query: str, embedder: Embedder) -> list[RetrievedChunk]:
|
| 52 |
+
query_embedding = embedder.embed_query(query)
|
| 53 |
+
documents, metadatas, distances = query_store(query_embedding, TOP_K_CANDIDATES)
|
| 54 |
+
|
| 55 |
+
if not documents:
|
| 56 |
+
return []
|
| 57 |
+
|
| 58 |
+
candidate_embeddings = embedder.embed_passages(documents)
|
| 59 |
+
selected_indices = _mmr(query_embedding, candidate_embeddings, metadatas, TOP_K_FINAL)
|
| 60 |
+
|
| 61 |
+
return [
|
| 62 |
+
RetrievedChunk(
|
| 63 |
+
text=documents[idx],
|
| 64 |
+
source_file=metadatas[idx]["source_file"],
|
| 65 |
+
page_number=metadatas[idx]["page_number"],
|
| 66 |
+
score=1.0 - distances[idx],
|
| 67 |
+
)
|
| 68 |
+
for idx in selected_indices
|
| 69 |
+
]
|