from __future__ import annotations import argparse from pathlib import Path import pandas as pd from pet_vlm_dataset import load_suvr_vector def readable_region_name(name: str) -> str: side = "" stem = name if name.endswith("_L"): side = "left " stem = name[:-2] elif name.endswith("_R"): side = "right " stem = name[:-2] stem = stem.replace("_", " ").lower() return f"{side}{stem}".strip() def make_region_text(labels: list[str], values: list[float], top_k: int) -> tuple[str, list[str], list[str]]: pairs = sorted(zip(labels, values), key=lambda item: item[1]) low = pairs[:top_k] high = pairs[-top_k:][::-1] low_text = ", ".join(readable_region_name(name) for name, _ in low) high_text = ", ".join(readable_region_name(name) for name, _ in high) text = ( "FDG-PET regional metabolic summary. " f"Relatively low metabolism is observed in {low_text}. " f"Relatively high uptake is observed in {high_text}." ) return text, [name for name, _ in low], [name for name, _ in high] def generate(manifest_path: Path, out_path: Path, top_k: int) -> None: manifest = pd.read_csv(manifest_path) rows = [] for row in manifest.to_dict(orient="records"): labels, suvr = load_suvr_vector(row["suvr_csv_path"], include_background=False) text, low_regions, high_regions = make_region_text(labels, suvr.tolist(), top_k) enriched = dict(row) enriched["region_text"] = text enriched["low_regions"] = "|".join(low_regions) enriched["high_regions"] = "|".join(high_regions) enriched["top_k"] = top_k rows.append(enriched) out_path.parent.mkdir(parents=True, exist_ok=True) pd.DataFrame(rows).to_csv(out_path, index=False) print(f"wrote {len(rows)} rows to {out_path}") def main() -> None: parser = argparse.ArgumentParser(description="Generate controlled region-text summaries from SUVR profiles.") parser.add_argument("--manifest", type=Path, required=True) parser.add_argument("--out", type=Path, required=True) parser.add_argument("--top-k", type=int, default=5) args = parser.parse_args() generate(args.manifest, args.out, args.top_k) if __name__ == "__main__": main()