| 174 | |
| 175 | |
| 176 | def write_summary(results: list[CaseResult], result_dir: Path) -> None: |
| 177 | succeeded = [r for r in results if r.success] |
| 178 | failed = [r for r in results if not r.success] |
| 179 | |
| 180 | per_task: dict[str, dict] = {} |
| 181 | for r in results: |
| 182 | if r.task not in per_task: |
| 183 | per_task[r.task] = {"total": 0, "success": 0, "failed": 0, "total_audio_s": 0.0, "total_gen_s": 0.0} |
| 184 | per_task[r.task]["total"] += 1 |
| 185 | if r.success: |
| 186 | per_task[r.task]["success"] += 1 |
| 187 | per_task[r.task]["total_audio_s"] += r.audio_duration |
| 188 | per_task[r.task]["total_gen_s"] += r.generation_time |
| 189 | else: |
| 190 | per_task[r.task]["failed"] += 1 |
| 191 | |
| 192 | for task, stats in per_task.items(): |
| 193 | if stats["total_audio_s"] > 0: |
| 194 | stats["avg_rtf"] = round(stats["total_gen_s"] / stats["total_audio_s"], 3) |
| 195 | |
| 196 | summary = { |
| 197 | "total_cases": len(results), |
| 198 | "succeeded": len(succeeded), |
| 199 | "failed": len(failed), |
| 200 | "per_task": per_task, |
| 201 | } |
| 202 | |
| 203 | if failed: |
| 204 | summary["failures"] = [ |
| 205 | {"task": r.task, "case_id": r.case_id, "error": r.error} |
| 206 | for r in failed |
| 207 | ] |
| 208 | |
| 209 | summary_path = result_dir / "inference_summary.json" |
| 210 | with open(summary_path, "w") as f: |
| 211 | json.dump(summary, f, indent=2, ensure_ascii=False) |
| 212 | log.info("Summary written to %s", summary_path) |
| 213 | |
| 214 | print("\n" + "=" * 60) |
| 215 | print(" BATCH INFERENCE SUMMARY") |
| 216 | print("=" * 60) |
| 217 | print(f" Total: {len(results)}") |
| 218 | print(f" Succeeded: {len(succeeded)}") |
| 219 | print(f" Failed: {len(failed)}") |
| 220 | for task, stats in per_task.items(): |
| 221 | rtf = stats.get("avg_rtf", "N/A") |
| 222 | print(f" {task}: {stats['success']}/{stats['total']} RTF={rtf}") |
| 223 | print("=" * 60 + "\n") |
| 224 | |
| 225 | |
| 226 | def main(): |