"""Сборка строкового транскрипта сеанса из реконструированных фраз. Формат строки — `[Имя MM:SS] текст` (или `[Имя ЧЧ:MM:SS] текст` от часа) — ровно тот, что ожидает утверждённый map-промпт суммаризации (`workers/summarizer/prompts/summary_map_ru.txt`) и парсит чанкер (`backend/core/summarization/chunking.py`). """ from collections.abc import Sequence from dataclasses import dataclass @dataclass(frozen=True, slots=True) class TranscriptLine: """Одна фраза транскрипта, готовая к форматированию в строку промпта. `offset_s` — смещение начала фразы в секундах от `t_start` сеанса (как у `PhraseDraft`, см. `workers/transcription/phrases.py`). """ speaker: str offset_s: float text: str def _format_offset(offset_s: float) -> str: """Отформатировать смещение как `MM:SS`, либо `ЧЧ:MM:SS` при offset >= 1 часа.""" total_seconds = int(offset_s) hours, remainder = divmod(total_seconds, 3600) minutes, seconds = divmod(remainder, 60) if hours: return f"{hours}:{minutes:02d}:{seconds:02d}" return f"{minutes:02d}:{seconds:02d}" def build_transcript(lines: Sequence[TranscriptLine]) -> str: """Собрать транскрипт сеанса: сортировка по `offset_s` → строки-фразы. Пустой список фраз даёт пустую строку. """ ordered = sorted(lines, key=lambda line: line.offset_s) return "\n".join( f"[{line.speaker} {_format_offset(line.offset_s)}] {line.text}" for line in ordered )