"""Formatação do texto que os handlers devolvem — tabelas e relatórios. Extraído de _shared.py — ver server_tools/_shared/__init__.py. """ from __future__ import annotations from typing import Sequence def format_timecode(tc) -> str: """Format a Timecode object to SMPTE string.""" return tc.to_smpte() if tc else "00:00:00:00" def format_duration(seconds: float) -> str: """Format seconds into human-readable duration.""" if seconds < 1: return f"{seconds*1000:.0f}ms" elif seconds < 60: return f"{seconds:.2f}s" return f"{int(seconds // 60)}m {seconds % 60:.1f}s" def _format_clip_table(clips: list, header: str) -> str: """Render a list of clips as a markdown table with timecodes and durations. Shared by handlers that filter clips by duration threshold (find_short_cuts, find_long_clips). """ result = f"{header}\n\n| Name | TC | Duration |\n|------|----|---------|\n" result += "\n".join( f"| {c.name} | {format_timecode(c.start)} | {format_duration(c.duration_seconds)} |" for c in clips ) return result def _markdown_table(headers: list[str], rows: list[list[str]]) -> str: """Build a markdown table from headers and rows. Returns header row, separator row, and data rows as a single string. Callers avoid repeating the ``| H1 | H2 |\\n|---|---|`` boilerplate that appears in 15+ handlers. """ header_line = "| " + " | ".join(headers) + " |" sep_line = "|" + "|".join("------" for _ in headers) + "|" data_lines = "\n".join( "| " + " | ".join(str(c) for c in row) + " |" for row in rows ) return f"{header_line}\n{sep_line}\n{data_lines}" def _format_batch_result( title: str, summary: dict[str, str], headers: list[str], rows: list[list[str]], output_path: str, ) -> str: """Build a standard batch-operation result with summary, table, and save footer. Used by batch fix handlers (flash frames, rapid trim, fill gaps) that all share the same markdown structure: ``# Title → ## Summary → ## Details table → Saved to`` footer. """ summary_lines = "\n".join(f"- **{k}**: {v}" for k, v in summary.items()) table = _markdown_table(headers, rows) return ( f"# {title}\n\n" f"## Summary\n{summary_lines}\n\n" f"## Details\n{table}\n\n" f"Saved to: `{output_path}`" ) def _fmt_suggestions(suggestions: list[str]) -> str: """Format pacing suggestions as markdown list (Python 3.10 compatible).""" if not suggestions: return "- Pacing looks good!" nl = "\n" return nl.join(f"- {s}" for s in suggestions) def _voice_analysis_config_text(config: dict) -> str: w = config["emphasis_weights"] text = "# Voice Analysis Settings\n\n" text += _markdown_table( ["Setting", "Value"], [ ["Energy threshold", f"{config['energy_threshold']:.2f}"], ["Peak selection", f"top {config['peak_percentile']:.1%} of words"], ["Emphasis floor", f"{config['emphasis_floor']:.2f}"], ["Emotion detection", "on" if config["emotion_enabled"] else "off"], ["Emotion sensitivity", f"{config['emotion_sensitivity']:.2f}"], ], ) + "\n\n## Emphasis Weights\n" text += _markdown_table( ["Factor", "Weight"], [[k.replace("_", " ").title(), f"{v:.2f}"] for k, v in w.items()], ) return text def _speaker_table(profiles: Sequence[dict]) -> str: """Who was detected, ordered by how much of the runtime each holds.""" return _markdown_table( ["ID", "Name", "Share", "Speaking", "Lines", "Avg line"], [ [ p["id"], p.get("name", ""), f"{p['share']:.0%}", format_duration(p["speaking_seconds"]), str(p["segment_count"]), f"{p['avg_segment']:.1f}s", ] for p in profiles ], )