"""Markdown reports for generation runs.""" from __future__ import annotations from pathlib import Path from typing import Any from .common import COMMON_DURATION_BEATS, Symbol def write_generation_report( *, output_dir: Path, title: str, description: str, settings: dict[str, Any], stats: dict[str, Any], generated: list[tuple[Symbol, ...]], write_abc: bool, write_musicxml: bool = False, ) -> None: lines = [ f"# {title}", "", description, "", "## Settings", "", ] for key, value in settings.items(): lines.append(f"- {key}: {value}") lines += [ "", "## Common Training Symbols", "", "| symbol | count |", "| --- | ---: |", ] for symbol, count in stats["top_symbols"]: lines.append(f"| `{symbol}` | {count} |") lines += ["", "## Common Durations", "", "| duration | count |", "| --- | ---: |"] for duration, count in stats["top_durations"]: lines.append(f"| {duration} | {count} |") lines += ["", "## Generated Samples", ""] for index, sequence in enumerate(generated, start=1): rpc_text = " ".join(str(symbol.rpc) for symbol in sequence) dur_text = " ".join(symbol.duration for symbol in sequence) lines += [ f"### Sample {index:02d}", "", f"- MIDI: `generated_{index:02d}.mid`", ] if write_abc: lines.append(f"- ABC: `generated_{index:02d}.abc`") if write_musicxml: lines.append(f"- MusicXML: `generated_{index:02d}.musicxml`") lines += [ f"- relative pcs: `{rpc_text}`", f"- durations: `{dur_text}`", "", ] (output_dir / "report.md").write_text("\n".join(lines), encoding="utf-8") def format_allowed_durations(allowed_durations: set[str]) -> str: return ", ".join(sorted(allowed_durations, key=COMMON_DURATION_BEATS.get))