"""Чанкинг транскрипта для map-стадии суммаризации (ТЗ §1.3). Транскрипт — строка с одной фразой на строку в формате `[Имя MM:SS] текст` (или `[Имя ЧЧ:MM:SS] текст` от часа, см. `workers/summarizer/transcript.py`). Каждая строка уже атомарна и соответствует одной реконструированной фразе (`build_phrases`) — граница фразы там уже равна смене спикера, поэтому `chunk_transcript` закрывает чанк исключительно на границах строк и никогда не режет фразу пополам (кроме аварийного случая монолога, см. ниже). Правила закрытия чанка (проверяются перед добавлением очередной фразы): - добавление фразы сделало бы охваченный чанком промежуток времени (от начала чанка до начала этой фразы) >= `target_chunk_minutes`; - ЛИБО добавление фразы превысило бы `max_chunk_tokens` для чанка. В любом из этих случаев уже накопленный чанк закрывается, а фраза уходит в новый чанк. Аварийный случай — монолог: единственная фраза сама по себе превышает `max_chunk_tokens` (например, 40-минутный монолог одного участника). Такую фразу нельзя оставить целой и нельзя просто выбросить — она делится по границам предложений на несколько частей меньше лимита, каждая из которых получает повторённую исходную метку `[Имя MM:SS]`, и добавляется в список чанков как самостоятельный чанк. """ import re from collections.abc import Callable _LABEL_RE = re.compile(r"^\[(?P.+) (?P