#!/usr/bin/env python3 """ Build per-(model, mode) manifests for the model × gallery-mode bake-off. Modes: full — every film matches against the whole model gallery (2418 actors) restricted — each film matches only its Jellyfin credited cast (~15 top-billed), via a per-film gallery filtered from the model gallery by jellyfin_id. Each manifest is a list of {name, xray, slug, dump, gallery} — no "movie" path (that's resolved locally via experiments/file-lut.json, see run_montage_all.py, to avoid embedding source filenames in a file that gets shared as an artifact). optimize.py reads film["gallery"] per film, so restricted mode just points each film at its own filtered gallery — no optimizer change needed. Writes experiments/manifests/films__.json and the restricted galleries to experiments/galleries/restricted//.h5. """ import json import sys from pathlib import Path REPO = Path(__file__).resolve().parent.parent sys.path.insert(0, str(REPO / "scripts" / "validation")) sys.path.insert(0, str(REPO / "scripts")) from identity import norm_name # noqa: E402 from sae_gallery import load_gallery_hdf5, save_gallery_hdf5 # noqa: E402 MODELS = ["arcface_w600k_r50", "arcface_r18", "arcface_w600k_mbf", "LVFace-B_Glint360K"] films = json.loads((REPO / "experiments/manifests/films.json").read_text()) casts = json.loads((REPO / "experiments/manifests/jellyfin_casts.json").read_text()) def restrict_gallery(model_gallery: dict, cast_ids: set[str]) -> dict: kept = [a for a in model_gallery["actors"] if a.get("jellyfin_id", "") in cast_ids] return {"actors": kept} for model in MODELS: gpath = REPO / f"experiments/galleries/gallery_{model}.h5" if not gpath.exists(): print(f"skip {model}: gallery not built yet ({gpath})") continue model_gal = load_gallery_hdf5(gpath) # full mode full = [{**f, "dump": f"experiments/dumps/{model}/dump_{f['slug']}.h5", "gallery": f"experiments/galleries/gallery_{model}.h5"} for f in films] (REPO / f"experiments/manifests/films_{model}_full.json").write_text(json.dumps(full, indent=2, ensure_ascii=False)) # restricted mode — per-film filtered gallery rdir = REPO / f"experiments/galleries/restricted/{model}" rdir.mkdir(parents=True, exist_ok=True) restr = [] for f in films: cast_ids = set(casts.get(f["name"], [])) rg = restrict_gallery(model_gal, cast_ids) rgpath = rdir / f"{f['slug']}.h5" save_gallery_hdf5(rg, rgpath) restr.append({**f, "dump": f"experiments/dumps/{model}/dump_{f['slug']}.h5", "gallery": str(rgpath.relative_to(REPO)), "_cast_size": len(rg["actors"])}) (REPO / f"experiments/manifests/films_{model}_restricted.json").write_text(json.dumps(restr, indent=2, ensure_ascii=False)) avg = sum(r["_cast_size"] for r in restr) / len(restr) print(f"{model}: full (2418) + restricted (avg {avg:.0f} actors/film) manifests written")