Files
cdsl-cad/cadfs_to_cdsl/reports.py
T
2026-09-02 13:51:35 +08:00

51 lines
3.2 KiB
Python

from __future__ import annotations
import csv, json
from collections import Counter, defaultdict
from pathlib import Path
from typing import Any
def write_json(path: Path, value: Any) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
temporary = path.with_suffix(path.suffix + ".tmp")
temporary.write_text(json.dumps(value, ensure_ascii=True, indent=2, sort_keys=True) + "\n", encoding="utf-8")
temporary.replace(path)
def read_json(path: Path) -> Any: return json.loads(path.read_text(encoding="utf-8"))
def write_manifest(path: Path, records: list[dict[str, Any]]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text("".join(json.dumps(item, ensure_ascii=True, sort_keys=True) + "\n" for item in records), encoding="utf-8")
def generate_reports(output: Path, records: list[dict[str, Any]]) -> dict[str, Any]:
statuses = Counter(str(item.get("status") or "unknown") for item in records)
operations: Counter[str] = Counter(); reasons: Counter[str] = Counter(); gaps: dict[str, list[str]] = defaultdict(list)
rows = []
for item in records:
sample_dir = output / "samples" / str(item["sample_id"])
diagnostics_path = sample_dir / "diagnostics.json"
if diagnostics_path.exists():
for diagnostic in read_json(diagnostics_path):
reasons[str(diagnostic.get("code") or "unknown")] += 1
if diagnostic.get("operation"): gaps[str(diagnostic["operation"])].append(str(item["sample_id"]))
history_path = sample_dir / "history.json"
if history_path.exists():
for step in read_json(history_path): operations[str(step.get("operation") or "unknown")] += 1
comparison_path = sample_dir / "comparison.json"
if comparison_path.exists():
comparison = read_json(comparison_path); metrics = comparison["raw"]["metrics"]
rows.append({"sample_id": item["sample_id"], "decision": comparison["decision"], "bbox_max_delta_mm": metrics["bbox_max_delta_mm"], "volume_relative_error": metrics["volume_relative_error"], "surface_area_relative_error": metrics["surface_area_relative_error"]})
summary = {"schema": "cadfs_to_cdsl.summary.v1", "total_models": len(records), "statuses": dict(statuses), "operation_counts": dict(operations), "failure_reasons": dict(reasons), "capability_gap_counts": {key: len(set(value)) for key, value in gaps.items()}}
write_json(output / "summary.json", summary)
gap_payload = {key: {"sample_count": len(set(ids)), "sample_ids": sorted(set(ids))} for key, ids in sorted(gaps.items())}; write_json(output / "capability_gaps.json", gap_payload)
lines = ["# Unsupported CADFS capabilities", ""]
for name, value in gap_payload.items(): lines.extend([f"## {name}", "", f"Affected models: {value['sample_count']}", "", "Sample IDs: " + ", ".join(value["sample_ids"]), ""])
(output / "unsupported_capabilities.md").write_text("\n".join(lines), encoding="utf-8")
with (output / "comparison_summary.csv").open("w", newline="", encoding="utf-8") as handle:
writer = csv.DictWriter(handle, fieldnames=["sample_id", "decision", "bbox_max_delta_mm", "volume_relative_error", "surface_area_relative_error"]); writer.writeheader(); writer.writerows(rows)
return summary