Download server/eval/precision.py from benroshan/Prism: direct link, hf CLI and curl.
- Browser
- Download file 2.42 kB
-
https://huggingface.co/spaces/benroshan/Prism/resolve/main/server/eval/precision.py
- Command line
-
hf download hf://spaces/benroshan/Prism/server/eval/precision.py
-
curl -L -o precision.py https://huggingface.co/spaces/benroshan/Prism/resolve/main/server/eval/precision.py
2.42 kB
| import json | |
| from server.retriever import retrieve_with_scores | |
| from server.utils import setup_logger | |
| logger = setup_logger(__name__) | |
| def compute_precision_at_k(query: str, retrieved_chunks: list[dict], ground_truth: dict, k: int = 5) -> float: | |
| """ | |
| Precision@K = (relevant chunks in top-K) / K | |
| A chunk is "relevant" if: | |
| - Its source matches ground_truth["relevant_sources"], OR | |
| - Its content contains any keyword from ground_truth["relevant_chunk_keywords"] | |
| Return float between 0 and 1. | |
| """ | |
| relevant_sources = ground_truth.get("relevant_sources", []) | |
| keywords = ground_truth.get("relevant_chunk_keywords", []) | |
| top_k = retrieved_chunks[:k] | |
| relevant_count = 0 | |
| for chunk in top_k: | |
| source_match = chunk.get("source", "") in relevant_sources | |
| keyword_match = any( | |
| kw.lower() in chunk.get("content", "").lower() for kw in keywords | |
| ) | |
| if source_match or keyword_match: | |
| relevant_count += 1 | |
| precision = relevant_count / k if k > 0 else 0.0 | |
| return round(precision, 4) | |
| def run_batch_precision_eval(eval_pairs_path: str, k: int = 5) -> dict: | |
| """ | |
| Run precision@K for all queries in eval_pairs.json. | |
| Return dict with mean_precision_at_k and per_query_results. | |
| """ | |
| with open(eval_pairs_path, "r") as f: | |
| eval_pairs = json.load(f) | |
| per_query_results = [] | |
| for pair in eval_pairs: | |
| query = pair["query"] | |
| retrieved = retrieve_with_scores(query, k=k) | |
| precision = compute_precision_at_k(query, retrieved, pair, k=k) | |
| retrieved_sources = [c["source"] for c in retrieved] | |
| per_query_results.append({ | |
| "query": query, | |
| "precision_at_k": precision, | |
| "retrieved_sources": retrieved_sources, | |
| }) | |
| logger.info(f"P@{k}={precision:.2f} | {query[:60]}...") | |
| mean_precision = sum(r["precision_at_k"] for r in per_query_results) / len(per_query_results) | |
| return { | |
| "mean_precision_at_k": round(mean_precision, 4), | |
| "per_query_results": per_query_results, | |
| } | |
| def run_batch_precision_eval_multi_k(eval_pairs_path: str, ks: list[int]) -> dict: | |
| """ | |
| Run precision evaluation for multiple K values. | |
| Return a dict keyed by precision@K. | |
| """ | |
| results = {} | |
| for k in ks: | |
| results[f"precision@{k}"] = run_batch_precision_eval(eval_pairs_path, k=k) | |
| return results | |