Spaces:
Running
Running
File size: 3,503 Bytes
74e8a7b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | """
ChromaDB collection access and similarity/metadata search.
"""
import chromadb
from src.utils.config import DB_PATH, COLLECTION_NAME, SIMILARITY_THRESHOLD
from src.knowledge_base.embeddings import embed_texts_with_retry
_client = chromadb.PersistentClient(path=DB_PATH)
collection = _client.get_collection(COLLECTION_NAME)
def search(
query: str,
top_k: int = 3,
metadata_filter: dict | None = None,
where: dict | None = None,
is_exact_fetch: bool = False,
) -> dict:
"""
Embed query and search ChromaDB.
metadata_filter: optional 'where' clause for similarity search.
where: 'where' clause for a direct metadata lookup (used when is_exact_fetch=True).
is_exact_fetch: skip embedding similarity entirely and fetch ALL chunks matching `where`
via collection.get(). Used for structured category lookups
(study_plan / program_info / scholarship / all_programs comparison)
where the whole matching set is wanted, not a top-k similarity guess.
NOTE: matches current notebook behavior β has_answer is returned True even when
documents is empty on the exact-fetch path (only a warning is printed). This means
the fallback-to-similarity-search in multi_query_search never actually triggers on
a truly empty exact-fetch result. Recommend restoring an `if documents:` guard here
if you want the fallback to work as originally intended β flagging for your decision.
"""
# ββ Study plan: direct metadata lookup, no ranking βββββββββββββββββ
if is_exact_fetch and where:
results = collection.get(where=where)
documents = results["documents"]
metadatas = results["metadatas"]
if not documents:
print(" [search] No exact-category chunks matched β falling back to similarity search")
scores = [1.0] * len(documents)
return {"has_answer": True, "documents": documents, "metadatas": metadatas,
"scores": scores, "best_score": 1.0}
# ββ Embedding-based similarity search ββββββββββββββββββββββββββββββ
query_embedding = embed_texts_with_retry([query])[0]
query_params = dict(
query_embeddings=[query_embedding],
n_results=top_k,
include=["documents", "metadatas", "distances"],
)
if metadata_filter:
query_params["where"] = metadata_filter
results = collection.query(**query_params)
documents = results["documents"][0]
metadatas = results["metadatas"][0]
distances = results["distances"][0]
# Fallback: if filter matched nothing, retry without the filter
if not documents and metadata_filter:
query_params.pop("where", None)
results = collection.query(**query_params)
documents = results["documents"][0]
metadatas = results["metadatas"][0]
distances = results["distances"][0]
if not documents:
return {"has_answer": False, "documents": [], "metadatas": [], "scores": [], "best_score": 0.0}
scores = [1 - d for d in distances]
best_score = max(scores)
if best_score < SIMILARITY_THRESHOLD:
return {"has_answer": False, "documents": [], "metadatas": [], "scores": [], "best_score": best_score}
return {"has_answer": True, "documents": documents, "metadatas": metadatas, "scores": scores, "best_score": best_score}
|