| """Thorough remote real-life vs anime eval (multi-model) + optional local video check. |
| |
| Writes JSON under scripts/out/ and prints a definitive GO/NO_GO conclusion. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import json |
| import logging |
| import os |
| import sys |
| from datetime import datetime, timezone |
| from pathlib import Path |
|
|
| ROOT = Path(__file__).resolve().parents[1] |
| REPO = ROOT.parent |
| sys.path.insert(0, str(ROOT)) |
|
|
| from app.realism_eval import predict_real_life, run_realism_eval_multi_model |
| from app.schemas import AppSettings |
| from app.services import VIDEO_EXTENSIONS, extract_scores_with_experimental_media |
| from app.storage import init_db |
| from app.taxonomy import reload_taxonomy |
|
|
| logging.basicConfig( |
| level=logging.INFO, |
| format="%(asctime)s %(levelname)s [%(name)s] %(message)s", |
| ) |
| logger = logging.getLogger("run_realism_debug_eval") |
|
|
|
|
| def _settings_from_db() -> AppSettings: |
| from app.api import _settings_from_db as load |
|
|
| return load() |
|
|
|
|
| def _probe_local_videos(settings: AppSettings, model: str, limit: int = 8) -> dict: |
| """Score local videos with multi-frame pooling if present.""" |
| roots = [] |
| if settings.root_repo: |
| roots.append(Path(settings.root_repo).expanduser()) |
| extra = os.environ.get("THR3SHR_VIDEO_PROBE_ROOT", "").strip() |
| if extra: |
| roots.append(Path(extra).expanduser()) |
| videos: list[Path] = [] |
| for root in roots: |
| if root is None or not root.is_dir(): |
| continue |
| for path in root.iterdir(): |
| if path.suffix.lower() in VIDEO_EXTENSIONS and path.is_file(): |
| videos.append(path) |
| if videos: |
| break |
| videos = sorted(videos)[:limit] |
| items = [] |
| for path in videos: |
| try: |
| scores = extract_scores_with_experimental_media( |
| path, |
| experimental_media_enabled=True, |
| tagger_model=model, |
| wd_general_threshold=settings.wd_general_threshold, |
| ) |
| is_rl, folder, score, evidence = predict_real_life( |
| scores, |
| selected={"real_life", "photo", *(settings.selected_tags or [])}, |
| ) |
| items.append( |
| { |
| "path": str(path), |
| "predicted_real_life": is_rl, |
| "folder": folder, |
| "score": score, |
| "evidence": evidence, |
| } |
| ) |
| except Exception as err: |
| items.append({"path": str(path), "error": str(err)}) |
| return { |
| "model": model, |
| "count": len(items), |
| "predicted_real_life": sum(1 for i in items if i.get("predicted_real_life")), |
| "items": items, |
| } |
|
|
|
|
| def main() -> int: |
| init_db() |
| reload_taxonomy() |
| settings = _settings_from_db() |
| count = int(sys.argv[1]) if len(sys.argv) > 1 else 16 |
| count = max(8, min(count, 40)) |
|
|
| logger.info("starting multi-model realism eval count_per_class=%s", count) |
| multi = run_realism_eval_multi_model(count_per_class=count, settings=settings) |
| best = multi.get("best_model") or "wd_eva02_large" |
| logger.info("probing local videos with best_model=%s", best) |
| video_probe = _probe_local_videos(settings, best, limit=10) |
|
|
| out_dir = Path(__file__).resolve().parent / "out" |
| out_dir.mkdir(parents=True, exist_ok=True) |
| stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") |
| payload = { |
| "generated_at": datetime.now(timezone.utc).isoformat(), |
| "multi_model": multi, |
| "local_video_probe": video_probe, |
| } |
| out_path = out_dir / f"realism_debug_eval_{stamp}.json" |
| latest = out_dir / "realism_debug_eval_latest.json" |
| text = json.dumps(payload, indent=2) |
| out_path.write_text(text, encoding="utf-8") |
| latest.write_text(text, encoding="utf-8") |
|
|
| overall = multi.get("overall_conclusion") or {} |
| print("=== REALISM DEBUG EVAL ===") |
| print("decision:", overall.get("decision")) |
| print("best_model:", overall.get("best_model")) |
| print("summary:", overall.get("summary")) |
| print("video:", overall.get("video_and_gif")) |
| for report in multi.get("reports") or []: |
| m = report.get("metrics") or {} |
| print( |
| f"- {report.get('tagger_model')}: {report.get('conclusion', {}).get('decision')} " |
| f"P={m.get('precision')} R={m.get('recall')} F1={m.get('f1')} " |
| f"animeFP={m.get('anime_false_positive_rate')} n={report.get('count_evaluated')}" |
| ) |
| print("local_video_predicted_real_life:", video_probe.get("predicted_real_life"), "/", video_probe.get("count")) |
| print("wrote", out_path) |
| return 0 if overall.get("decision") == "GO" else 2 |
|
|
|
|
| if __name__ == "__main__": |
| raise SystemExit(main()) |
|
|