Spaces:
Sleeping
Sleeping
| """ | |
| Fills r3_* (Fine-Tuned) metrics into existing benchmark_cache.json. | |
| Run this ONCE after system3_inference.py is updated to use checkpoint-25/. | |
| python fill_r3.py | |
| """ | |
| import os, json, time | |
| import numpy as np | |
| # rouge_score MUST come before any heavy ML imports | |
| from rouge_score import rouge_scorer as rs | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| # ββ ML imports AFTER rouge_score ββββββββββββββββββββββββββββββββββββββββββββββ | |
| from langchain_huggingface import HuggingFaceEmbeddings | |
| from langchain_community.vectorstores import FAISS | |
| from system3_inference import ask_finetuned # now points to checkpoint-25 | |
| # ββ Load reference answers ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| with open("data/reference_answers.json", encoding="utf-8") as f: | |
| ref_answers = json.load(f) | |
| # ββ Load embeddings + vector store (for metric computation) ββββββββββββββββββ | |
| INDEX_PATH = "data/faiss_index" | |
| print("Loading embeddings / vector store...") | |
| emb = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2") | |
| vs = FAISS.load_local(INDEX_PATH, emb, allow_dangerous_deserialization=True) | |
| print("Ready.\n") | |
| scorer = rs.RougeScorer(["rougeL"], use_stemmer=True) | |
| def _cosine(a, b): | |
| n = np.linalg.norm(a) * np.linalg.norm(b) | |
| return float(np.dot(a, b) / (n + 1e-8)) | |
| def compute_metrics(answer: str, question: str) -> dict: | |
| if not answer or not answer.strip(): | |
| return {"accuracy": 0, "rouge_l": 0, "groundedness": 0, | |
| "answer_relevance": 0, "faithfulness": 0} | |
| try: | |
| a_emb = np.array(vs.embeddings.embed_query(answer)) | |
| q_emb = np.array(vs.embeddings.embed_query(question)) | |
| answer_relevance = round(max(0.0, _cosine(a_emb, q_emb)), 3) | |
| ref = ref_answers.get(question.strip().lower(), "") | |
| accuracy, rouge_l = 0.0, 0.0 | |
| if ref: | |
| rouge_l = round(scorer.score(ref, answer)["rougeL"].fmeasure, 3) | |
| r_emb = np.array(vs.embeddings.embed_query(ref)) | |
| accuracy = round(max(0.0, _cosine(a_emb, r_emb)), 3) | |
| # For fine-tuned: no retrieval context, so groundedness = accuracy, faithfulness = rouge_l | |
| return {"accuracy": accuracy, "rouge_l": rouge_l, | |
| "groundedness": accuracy, "answer_relevance": answer_relevance, | |
| "faithfulness": rouge_l} | |
| except Exception as e: | |
| print(f" [metric error] {e}") | |
| return {"accuracy": 0, "rouge_l": 0, "groundedness": 0, | |
| "answer_relevance": 0, "faithfulness": 0} | |
| def _cost(answer: str) -> float: | |
| tokens = max(1, len(answer.split())) | |
| return round(tokens * 0.0000015, 4) # local model, near-zero cost | |
| # ββ Load existing cache βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| OUT_PATH = "data/benchmark_cache.json" | |
| with open(OUT_PATH, encoding="utf-8") as f: | |
| results = json.load(f) | |
| total = len(results) | |
| print(f"Filling r3 values for {total} cached questions...\n") | |
| print("(Loading fine-tuned model on first question β ~30s)\n") | |
| for i, row in enumerate(results): | |
| q = row["question"] | |
| print(f"[{i+1:02d}/{total}] {q[:65]}") | |
| r3 = ask_finetuned(q) | |
| answer = r3.get("answer", "") | |
| elapsed = r3.get("response_time", 0) | |
| m = compute_metrics(answer, q) | |
| row["r3_time"] = elapsed | |
| row["r3_rouge"] = m["rouge_l"] | |
| row["r3_sim"] = m["accuracy"] | |
| row["r3_ground"] = m["groundedness"] | |
| row["r3_relev"] = m["answer_relevance"] | |
| row["r3_faith"] = m["faithfulness"] | |
| row["r3_cost"] = _cost(answer) | |
| print(f" r3_acc={m['accuracy']:.3f} r3_rouge={m['rouge_l']:.3f} time={elapsed}s") | |
| # Save after every row so we can resume on crash | |
| with open(OUT_PATH, "w", encoding="utf-8") as f: | |
| json.dump(results, f, indent=2) | |
| # ββ Summary βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| n = len(results) | |
| r3_acc = round(sum(r["r3_sim"] for r in results) / n * 100, 1) | |
| r3_rl = round(sum(r["r3_rouge"] for r in results) / n, 3) | |
| r3_t = round(sum(r["r3_time"] for r in results) / n, 2) | |
| print(f"\nDone! r3 values saved to {OUT_PATH}") | |
| print(f" Fine-Tuned β accuracy {r3_acc}% rouge_l {r3_rl} avg_time {r3_t}s") | |