Import sap-architecture skill
This commit is contained in:
@@ -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())
|
||||
Reference in New Issue
Block a user