From b10a5706f4328c73631d0149f0b03e6041fd5678 Mon Sep 17 00:00:00 2001 From: Mahdi Bazrafshan Date: Wed, 29 Jul 2026 17:54:26 +0330 Subject: [PATCH] feat(reports): add overall scores to strategy cards and average row in technical report Why: - Users need to see each strategy's overall score at a glance in the report - Technical report should show average metrics across all strategies Changes: - Each strategy card now shows its overall score below the metric bars - Technical report aggregate table includes an AVERAGE row across all strategies Impact: - Managerial report: strategy cards now show overall score - Technical report: aggregate table has a new AVERAGE row at the bottom --- src/benchmarking/report.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/benchmarking/report.py b/src/benchmarking/report.py index 53b5ba4..83985e0 100644 --- a/src/benchmarking/report.py +++ b/src/benchmarking/report.py @@ -633,6 +633,9 @@ def _build_strategy_cards(rankings: list, aggregate: dict) -> str: {_metric_bar("Similarity", m.get("avg_answer_similarity", 0), "accent")} {_metric_bar("Faithfulness", m.get("avg_faithfulness", 0), "violet")} {_metric_bar("No Hallucination", (1 - m.get("hallucination_rate", 0)) * 10, "teal" if m.get("hallucination_rate", 0) <= 0.1 else "rose")} +
+ Overall: {overall:.2f} +
""" return cards @@ -690,7 +693,7 @@ def _generate_decision_insights(rankings: list, aggregate: dict) -> str: def _build_technical_aggregate_rows(rankings: list, aggregate: dict) -> str: - """Build technical aggregate table rows.""" + """Build technical aggregate table rows with an average row at the end.""" rows = "" for rank, (strategy, overall) in enumerate(rankings, 1): m = aggregate.get(strategy, {}) @@ -705,6 +708,28 @@ def _build_technical_aggregate_rows(rankings: list, aggregate: dict) -> str: {m.get('failed_questions', 0)} {overall:.2f} """ + + # Average row across all strategies + n = len(rankings) + if n > 0: + avg_ctx = sum(aggregate.get(s, {}).get('avg_context_relevance', 0) for s, _ in rankings) / n + avg_sim = sum(aggregate.get(s, {}).get('avg_answer_similarity', 0) for s, _ in rankings) / n + avg_faith = sum(aggregate.get(s, {}).get('avg_faithfulness', 0) for s, _ in rankings) / n + avg_hall = sum(aggregate.get(s, {}).get('hallucination_rate', 0) for s, _ in rankings) / n + avg_total = sum(aggregate.get(s, {}).get('total_questions', 0) for s, _ in rankings) / n + avg_failed = sum(aggregate.get(s, {}).get('failed_questions', 0) for s, _ in rankings) / n + avg_overall = sum(overall for _, overall in rankings) / n + rows += f""" + + AVERAGE + {_pill(avg_ctx)} + {_pill(avg_sim)} + {_pill(avg_faith)} + {_hall_pill(avg_hall)} + {avg_total:.0f} + {avg_failed:.0f} + {avg_overall:.2f} + """ return rows