Import sap-architecture skill

This commit is contained in:
2026-07-24 20:47:16 +00:00
commit f3699e6f43
121 changed files with 127110 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env python3
"""Score one .drawio candidate against a corpus of SAP reference diagrams.
Use this after generating a diagram. The best match should usually be the
template you started from. If no reference scores high, the diagram probably
drifted away from SAP Architecture Center structure.
Usage:
score_corpus.py my-diagram.drawio
score_corpus.py --top 10 --min-score 90 my-diagram.drawio
score_corpus.py --references /path/to/SAP/architecture-center my-diagram.drawio
score_corpus.py --min-sap-like 90 semantic-diagram.drawio
"""
from __future__ import annotations
import argparse
import json
import sys
from dataclasses import asdict, dataclass
from pathlib import Path
from compare import compare, fingerprint, sap_likeness
from validate import validate
@dataclass
class RankedScore:
reference: str
score: float
breakdown: dict[str, float]
diffs: list[str]
def default_reference_dir() -> Path:
return Path(__file__).resolve().parents[1] / "assets" / "reference-examples"
def collect_references(paths: list[Path]) -> list[Path]:
refs: list[Path] = []
for p in paths:
if p.is_dir():
refs.extend(sorted(p.rglob("*.drawio")))
elif p.suffix.lower() == ".drawio":
refs.append(p)
return refs
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("candidate", type=Path)
ap.add_argument(
"--references",
type=Path,
action="append",
default=None,
help="reference .drawio file or directory; can be passed multiple times",
)
ap.add_argument("--top", type=int, default=5)
ap.add_argument("--min-score", type=float, default=None, help="exit 1 if best score is below this value")
ap.add_argument("--min-sap-like", type=float, default=None, help="exit 1 if reference-free SAP-likeness is below this value")
ap.add_argument("--json", action="store_true")
ap.add_argument("--score", action="store_true", help="print only the best score")
ap.add_argument("--sap-score", action="store_true", help="print only the reference-free SAP-likeness score")
args = ap.parse_args()
if not args.candidate.exists():
print(f"{args.candidate}: candidate not found", file=sys.stderr)
return 2
reference_inputs = args.references or [default_reference_dir()]
refs = collect_references(reference_inputs)
if not refs:
print("no reference .drawio files found", file=sys.stderr)
return 2
candidate_fp = fingerprint(args.candidate)
validation_report = validate(args.candidate)
quality = sap_likeness(candidate_fp, validator_errors=len(validation_report.errors))
ranked: list[RankedScore] = []
for ref in refs:
result = compare(fingerprint(ref), candidate_fp)
ranked.append(RankedScore(str(ref), result.score, result.breakdown, result.diffs))
ranked.sort(key=lambda r: (-r.score, r.reference))
top = ranked[: args.top]
best = top[0].score if top else 0.0
if args.score:
print(f"{best:.1f}")
elif args.sap_score:
print(f"{quality.score:.1f}")
elif args.json:
print(json.dumps({"sap_likeness": asdict(quality), "ranked": [asdict(r) for r in top]}, indent=2))
else:
print(f"candidate : {args.candidate}")
print(f"references: {len(refs)}")
print(f"best : {best:.1f}/100 corpus similarity")
print(f"sap-like : {quality.score:.1f}/100 reference-free quality")
if quality.issues:
print(f"sap issues: {quality.issues[0]}")
for i, item in enumerate(top, 1):
print(f"{i}. {item.score:5.1f} {item.reference}")
if item.diffs:
print(f" - {item.diffs[0]}")
if args.min_score is not None and best < args.min_score:
return 1
if args.min_sap_like is not None and quality.score < args.min_sap_like:
return 1
return 0
if __name__ == "__main__":
sys.exit(main())