1+ # src/ops_qa_auditor/summary.py
2+ from __future__ import annotations
3+
4+ import csv
5+ from dataclasses import dataclass
6+ from pathlib import Path
7+ from typing import Any
8+
9+
10+ @dataclass (frozen = True )
11+ class BatchSummary :
12+ total : int
13+ passed : int
14+ failed : int
15+ avg_score : float
16+
17+
18+ def build_batch_summary_payload (results : list [dict [str , Any ]]) -> dict [str , Any ]:
19+ scores = [int (r ["result" ]["score" ]["total" ]) for r in results ]
20+ passed = sum (1 for r in results if bool (r ["result" ]["score" ]["passed" ]))
21+ total = len (results )
22+ failed = total - passed
23+ avg = (sum (scores ) / total ) if total else 0.0
24+
25+ return {
26+ "summary" : {
27+ "total" : total ,
28+ "passed" : passed ,
29+ "failed" : failed ,
30+ "avg_score" : round (avg , 2 ),
31+ },
32+ "results" : [
33+ {
34+ "source_name" : r ["meta" ]["source_name" ],
35+ "score" : int (r ["result" ]["score" ]["total" ]),
36+ "passed" : bool (r ["result" ]["score" ]["passed" ]),
37+ "missing_required_phrases" : r ["result" ]["findings" ]["missing_required_phrases" ],
38+ "found_forbidden_phrases" : r ["result" ]["findings" ]["found_forbidden_phrases" ],
39+ "missing_required_sections" : r ["result" ]["findings" ]["missing_required_sections" ],
40+ }
41+ for r in results
42+ ],
43+ }
44+
45+
46+ def write_summary_json (out_path : Path , payload : dict [str , Any ]) -> None :
47+ import json
48+
49+ out_path .write_text (json .dumps (payload , indent = 2 , sort_keys = True ), encoding = "utf-8" )
50+
51+
52+ def write_summary_csv (out_path : Path , payload : dict [str , Any ]) -> None :
53+ rows = payload ["results" ]
54+ with out_path .open ("w" , newline = "" , encoding = "utf-8" ) as f :
55+ w = csv .writer (f )
56+ w .writerow (
57+ [
58+ "source_name" ,
59+ "score" ,
60+ "passed" ,
61+ "missing_required_phrases_count" ,
62+ "found_forbidden_phrases_count" ,
63+ "missing_required_sections_count" ,
64+ ]
65+ )
66+ for r in rows :
67+ w .writerow (
68+ [
69+ r ["source_name" ],
70+ r ["score" ],
71+ r ["passed" ],
72+ len (r ["missing_required_phrases" ]),
73+ len (r ["found_forbidden_phrases" ]),
74+ len (r ["missing_required_sections" ]),
75+ ]
76+ )
0 commit comments