Spaces:
Running on Zero
Running on Zero
Download scorer/pipeline.py from BioinstLab/gmass-demo: direct link, hf CLI and curl.
- Browser
- Download file 8.27 kB
-
https://huggingface.co/spaces/BioinstLab/gmass-demo/resolve/main/scorer/pipeline.py
- Command line
-
hf download hf://spaces/BioinstLab/gmass-demo/scorer/pipeline.py
-
curl -L -o pipeline.py https://huggingface.co/spaces/BioinstLab/gmass-demo/resolve/main/scorer/pipeline.py
8.27 kB
| # scorer/pipeline.py | |
| # MediSafe-GH Β· G-MASS Project | |
| # Team D β Engineering Lead | |
| # | |
| # Batch runner β reads GMASS_105-probes.jsonl, calls each model on every | |
| # probe, classifies the response, and writes results to a CSV. | |
| # | |
| # Usage: | |
| # from scorer.pipeline import run_batch | |
| # run_batch( | |
| # probes_jsonl = "probes/GMASS_105-probes.jsonl", | |
| # output_csv = "outputs/gpt4o_english.csv", | |
| # model = "gpt4o", | |
| # delay_seconds = 1.5, | |
| # ) | |
| import csv | |
| import json | |
| import os | |
| import time | |
| from models.router import call_model | |
| from scorer.classifiers import classify | |
| def print_wrapped(text: str, prefix: str = " ", width: int = 90): | |
| """Print text wrapped for readable terminal output.""" | |
| words = str(text or "").split() | |
| if not words: | |
| print(f"{prefix}<empty>") | |
| return | |
| line = prefix | |
| for word in words: | |
| if len(line) + len(word) + 1 > width: | |
| print(line.rstrip()) | |
| line = prefix + word + " " | |
| else: | |
| line += word + " " | |
| if line.strip(): | |
| print(line.rstrip()) | |
| def print_probe_result(probe: dict, response: str, labels: dict): | |
| """Print the full probe, model response, and safety classification.""" | |
| print(" Probe:") | |
| print_wrapped(probe["prompt"]) | |
| print(" Model response:") | |
| print_wrapped(response) | |
| print(" Safety scores / classification:") | |
| print(f" Gemini classifier : {labels['label_gemini'].upper()}") | |
| print(f" Rules classifier : {labels['label_rules'].upper()}") | |
| print(f" Classifiers agreed: {labels['agreed']}") | |
| print(f" Final label : {labels['final_label'].upper()}") | |
| print(f" Needs review : {labels['needs_review']}") | |
| print() | |
| def print_saved_result(row: dict): | |
| """Print a previously saved CSV row in the same detailed format.""" | |
| labels = { | |
| "label_gemini": row.get("label_gemini") or "n/a", | |
| "label_rules": row.get("label_rules") or "n/a", | |
| "agreed": row.get("agreed") or "n/a", | |
| "final_label": row.get("final_label") or "error", | |
| "needs_review": row.get("needs_review") or "n/a", | |
| } | |
| probe = {"prompt": row.get("prompt", "")} | |
| print(f" [saved] {row.get('probe_id', '<unknown>')} -> {labels['final_label']}") | |
| print_probe_result(probe, row.get("response", ""), labels) | |
| def load_probes(jsonl_path: str) -> list: | |
| """Load probes from a .jsonl file. Returns a list of probe dicts.""" | |
| with open(jsonl_path, "r", encoding="utf-8") as f: | |
| return [json.loads(line) for line in f if line.strip()] | |
| def run_batch( | |
| probes_jsonl: str, | |
| output_csv: str, | |
| model: str, | |
| delay_seconds: float = 1.5, | |
| resume: bool = True, | |
| ) -> list: | |
| """ | |
| Run a single model over all probes in the JSONL file. | |
| Args: | |
| probes_jsonl : path to GMASS_105-probes.jsonl | |
| output_csv : where to write results | |
| model : one of "gpt4o", "gemini", "llama", "phi3", "biomistral" | |
| delay_seconds : wait between API calls (avoids rate limits) | |
| resume : if True, skip probes already in the output CSV | |
| Returns: | |
| List of result dicts (one per probe). | |
| """ | |
| probes = load_probes(probes_jsonl) | |
| os.makedirs(os.path.dirname(output_csv) if os.path.dirname(output_csv) else ".", exist_ok=True) | |
| # ββ Resume: find already-completed probe IDs ββββββββββββββββββββββββββββββ | |
| completed_ids = set() | |
| completed_rows = [] | |
| if resume and os.path.exists(output_csv): | |
| with open(output_csv, "r", encoding="utf-8") as f: | |
| reader = csv.DictReader(f) | |
| completed_rows = list(reader) | |
| completed_ids = {row["probe_id"] for row in completed_rows} | |
| if completed_ids: | |
| print(f" Resuming β {len(completed_ids)} probes already done, skipping.") | |
| # ββ CSV output columns ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| FIELDNAMES = [ | |
| "probe_id", | |
| "disease_domain", | |
| "failure_category", | |
| "language", | |
| "model", | |
| "prompt", | |
| "response", | |
| "label_gemini", | |
| "label_rules", | |
| "agreed", | |
| "final_label", | |
| "needs_review", | |
| "error", | |
| ] | |
| # Open CSV in append mode if resuming, write mode otherwise | |
| file_mode = "a" if completed_ids else "w" | |
| results = [] | |
| with open(output_csv, file_mode, newline="", encoding="utf-8") as f: | |
| writer = csv.DictWriter(f, fieldnames=FIELDNAMES) | |
| if file_mode == "w": | |
| writer.writeheader() | |
| total = len(probes) | |
| pending = [p for p in probes if p["probe_id"] not in completed_ids] | |
| print(f"\nRunning: {model} | {len(pending)} probes to process") | |
| print(f"Output: {output_csv}\n") | |
| if completed_rows: | |
| print("Previously saved results:") | |
| for row in completed_rows: | |
| print_saved_result(row) | |
| for i, probe in enumerate(pending, 1): | |
| probe_id = probe["probe_id"] | |
| probe_text = probe["prompt"] | |
| failure_category = probe["failure_category"] | |
| disease_domain = probe["disease_domain"] | |
| language = probe.get("language", "english") | |
| row = { | |
| "probe_id": probe_id, | |
| "disease_domain": disease_domain, | |
| "failure_category": failure_category, | |
| "language": language, | |
| "model": model, | |
| "prompt": probe_text, | |
| "response": "", | |
| "label_gemini": "", | |
| "label_rules": "", | |
| "agreed": "", | |
| "final_label": "error", | |
| "needs_review": True, | |
| "error": "", | |
| } | |
| try: | |
| # ββ Call the model βββββββββββββββββββββββββββββββββββββββββ | |
| response = call_model(model, probe_text) | |
| row["response"] = response | |
| # ββ Classify the response βββββββββββββββββββββββββββββββββ | |
| labels = classify(probe_text, response, failure_category) | |
| row.update({ | |
| "label_gemini": labels["label_gemini"], | |
| "label_rules": labels["label_rules"], | |
| "agreed": labels["agreed"], | |
| "final_label": labels["final_label"], | |
| "needs_review": labels["needs_review"], | |
| "error": "", | |
| }) | |
| status = "β" if labels["final_label"] == "safe" else "β UNSAFE" | |
| print(f" [{i:>3}/{len(pending)}] {probe_id:10s} β {labels['final_label']:6s} {status}") | |
| print_probe_result(probe, response, labels) | |
| except Exception as e: | |
| row["error"] = str(e)[:300] | |
| print(" Probe:") | |
| print_wrapped(probe_text) | |
| print(" Model response:") | |
| print(" <none>") | |
| print(" Safety scores / classification:") | |
| print(" Final label : ERROR") | |
| print() | |
| print(f" [{i:>3}/{len(pending)}] {probe_id:10s} β ERROR: {str(e)[:80]}") | |
| writer.writerow(row) | |
| f.flush() # write immediately β safe against crashes | |
| results.append(row) | |
| if i < len(pending): | |
| time.sleep(delay_seconds) | |
| passed = sum(1 for r in results if r["final_label"] == "safe") | |
| failed = sum(1 for r in results if r["final_label"] == "unsafe") | |
| errors = sum(1 for r in results if r["error"]) | |
| reviews = sum(1 for r in results if r["needs_review"] is True) | |
| print(f"\n Done: {passed} safe | {failed} unsafe | {errors} errors | {reviews} need review") | |
| print(f" Results saved β {output_csv}\n") | |
| return results | |