SMSD75's picture
Update SynthScope Space from the GitHub repository
cd24b4a verified
Raw History Blame Contribute Delete
5.04 kB
"""``synthscope`` command-line interface.
synthscope list # list detectors and weight availability
synthscope detect FILE --model fat_former # score an image or video (auto-downloads weights)
synthscope detect FILE -m d3 --json # machine-readable output
synthscope pull --model clip # fetch a checkpoint from the model zoo
synthscope push --repo USER/synthscope-checkpoints # (maintainer) publish checkpoints to the Hub
"""
from __future__ import annotations
import argparse
import json
import sys
def _cmd_list(args: argparse.Namespace) -> int:
from . import list_models
models = list_models()
if args.json:
print(json.dumps(models, indent=2))
return 0
width = max(len(m["key"]) for m in models)
print(f"{'KEY'.ljust(width)} AVAIL MODALITY NAME")
for m in models:
mark = " ok " if m["available"] else " -- "
print(f"{m['key'].ljust(width)} {mark} {m['modality']:<8} {m['name']} ({m['paper']})")
if not args.json:
print("\n'--' = weights not found under $SYNTHSCOPE_CKPT_DIR (training-free models are always available).")
return 0
def _cmd_pull(args: argparse.Namespace) -> int:
from . import hub
path = hub.download(args.model, repo_id=args.repo)
print(f"downloaded {args.model} -> {path}")
return 0
def _cmd_push(args: argparse.Namespace) -> int:
from . import hub
keys = args.models.split(",") if args.models else None
summary = hub.push(
repo_id=args.repo,
keys=keys,
include_official=args.include_official,
private=not args.public,
dry_run=args.dry_run,
)
return 0 if (summary["uploaded"] or summary["dry_run"]) else 1
def _cmd_detect(args: argparse.Namespace) -> int:
from . import load
det = load(args.model, checkpoint=args.checkpoint, device=args.device,
auto_download=not args.no_download, repo=args.repo)
if not det.available:
print(
f"error: no weights for '{args.model}'. Place its checkpoint under $SYNTHSCOPE_CKPT_DIR "
f"or pass --checkpoint PATH (training-free models need none).",
file=sys.stderr,
)
return 2
result = det.predict(args.file, num_frames=args.frames)
if args.json:
print(json.dumps(result, indent=2))
else:
p = result["fake_probability"]
print(f"{result['model_name']} -> {result['verdict'].upper()} "
f"(P(fake)={p:.4f}, confidence={result['confidence']:.4f}, {result['elapsed_ms']:.0f} ms)")
return 0
def build_parser() -> argparse.ArgumentParser:
p = argparse.ArgumentParser(prog="synthscope", description="AI-generated image & video detection.")
sub = p.add_subparsers(dest="command", required=True)
pl = sub.add_parser("list", help="list available detectors")
pl.add_argument("--json", action="store_true", help="emit JSON")
pl.set_defaults(func=_cmd_list)
pd = sub.add_parser("detect", help="score an image or video file")
pd.add_argument("file", help="path to an image or video")
pd.add_argument("-m", "--model", required=True, help="detector key (see `synthscope list`)")
pd.add_argument("--checkpoint", default=None, help="override the .pth checkpoint path")
pd.add_argument("--device", default=None, help="cuda | cpu (default: cuda if available)")
pd.add_argument("--frames", type=int, default=None,
help="frames to sample when running an image detector on a video")
pd.add_argument("--repo", default=None, help="model-zoo Hub repo to download from")
pd.add_argument("--no-download", action="store_true", help="do not auto-download weights")
pd.add_argument("--json", action="store_true", help="emit JSON")
pd.set_defaults(func=_cmd_detect)
pp = sub.add_parser("pull", help="download a detector's checkpoint from the model zoo")
pp.add_argument("-m", "--model", required=True, help="detector key")
pp.add_argument("--repo", default=None, help="Hub repo (default: $SYNTHSCOPE_HUB_REPO)")
pp.set_defaults(func=_cmd_pull)
pu = sub.add_parser("push", help="(maintainer) publish checkpoints to the Hub model zoo")
pu.add_argument("--repo", default=None, help="target Hub repo id (default: $SYNTHSCOPE_HUB_REPO)")
pu.add_argument("--models", default=None, help="comma-separated keys (default: all eligible)")
pu.add_argument("--include-official", action="store_true",
help="also upload official-weights checkpoints (verify their license first!)")
pu.add_argument("--public", action="store_true", help="create a PUBLIC repo (default: private)")
pu.add_argument("--dry-run", action="store_true", help="report the selection, upload nothing")
pu.set_defaults(func=_cmd_push)
return p
def main(argv: list[str] | None = None) -> int:
args = build_parser().parse_args(argv)
return args.func(args)
if __name__ == "__main__":
raise SystemExit(main())