from __future__ import annotations from dataclasses import asdict import json from .analysis import CompositionAnalysis, analyze_composition from .types import CompositionRecord, CompositionRunReport def build_run_report( record: CompositionRecord, *, alphabet_size: int = 8, parameters: dict[str, object] | None = None, ) -> CompositionRunReport: analysis = analyze_composition(record.notes, alphabet_size=alphabet_size) return CompositionRunReport( notes=record.notes, per_note_seconds=record.per_note_seconds, total_seconds=record.total_seconds, parameters=parameters or {}, note_count=analysis.note_count, alphabet_size=analysis.alphabet_size, unigram_entropy_bits=analysis.unigram_entropy_bits, conditional_entropy_bits=analysis.conditional_entropy_bits, normalized_entropy=analysis.normalized_entropy, predictability=analysis.predictability, redundancy=analysis.redundancy, ) def save_run_report_json(report: CompositionRunReport, path: str) -> None: with open(path, "w", encoding="utf-8") as handle: json.dump(asdict(report), handle, indent=2)