- Зачем: - спецификация не должна оставлять неоднозначности перед реализацией диаризации. - Что: - уточнены сведение слов, таймкоды и предупреждение о малом кластере. - очищены терминология и граница между ADR и спецификацией. - сохранён результат сравнения WeSpeaker и CAMPPlus. - Проверка: - git diff --cached --check и проверка относительных ссылок.
16 KiB
Диаризация говорящих в транскрипте
Проблема
Текущий транскрипт знает только сегменты распознавания. Их границы проходят по тишине и не совпадают со сменой говорящего, поэтому один сегмент может содержать несколько реплик. Назначение одной метки всему сегменту искажает структуру диалога и делает транскрипт слабым сырьём для конспекта или протокола встречи.
ADR-007 выбирает явную
пословную диаризацию через sherpa-onnx. Эта спецификация фиксирует форму первой
реализации, не меняя принятые решения.
Цели
- По явному запросу строить реплики говорящих, сохраняя текст и длинный контекст ASR.
- Поддержать один контракт слов с временной привязкой на FasterWhisper, ONNX-ASR и OpenVINO.
- Сохранить предсказуемый single- и batch-режим при отсутствии речи, ошибках диаризации и малых голосовых кластерах.
- Выдать компактный Markdown, удобный и человеку, и последующей обработке LLM.
Не входит
- Автоматическое включение диаризации без флага и
--no-diarize. - Параллельный запуск ASR и диаризации.
- Сопоставление
Speaker Nс именами участников. - Постоянный кеш разметки говорящих, голосовые эмбеддинги и диагностические файлы.
- Отдельный синтаксис для перекрывающейся речи.
- Изменение устройства ASR или диаризации ради восстановления функции.
Пользовательский интерфейс
--diarizeвключает диаризацию. По умолчанию она выключена; ключ в.transcriber.tomlв первой версии не добавляется.--speakers N, гдеN >= 1, задаёт известное число участников и сам включает диаризацию. Без него число кластеров определяется автоматически.--threads Nостаётся единым бюджетом активного CPU-прохода. Значение целиком получает сначала ASR, затем диаризация;0оставляет настройки библиотек.--verboseпоказывает в консоли прогресс, число кластеров и интервалов, длительность прохода и предупреждения, но не создаёт дополнительные файлы.--forceпересчитывает и ASR, и диаризацию. Без него готовый транскрипт, как и сейчас, пропускается целиком.
sherpa-onnx входит в обычные runtime-зависимости. Модели
sherpa-onnx-pyannote-segmentation-3-0 и
wespeaker_en_voxceleb_resnet34_LM.onnx скачиваются и кешируются лениво при
первом запросе диаризации. Отдельного installation extra нет.
Контракты данных
Результат ASR сохраняет существующие сегменты распознавания и дополнительно содержит упорядоченные канонические слова. Для каждого слова известны текст, начало и конец на временной шкале исходной записи. Backend-специфичные токены и слова нормализуются в адаптере бэкенда; их обратная сборка должна сохранять распознанный текст с точностью до нормализации пробелов.
Разметка говорящих хранится отдельно от результата ASR: это упорядоченные временные интервалы с анонимным идентификатором голосового кластера. ASR-бэкенд не знает о кластерах, а диаризатор не знает о распознанном тексте.
Операция сведения суммирует временное перекрытие слова с интервалами каждого кластера и назначает кластер с единственным наибольшим ненулевым перекрытием. Если пересечения нет либо несколько кластеров делят наибольшее значение, слово получает неизвестного говорящего: порядок кластеров не используется как искусственная развязка ничьей. Соседние слова одного говорящего объединяются в реплику; порядок слов и исходная временная шкала не меняются.
Все три ASR-пути обязаны предоставлять пословный контракт до включения диаризации:
| Путь | Источник временных привязок |
|---|---|
| FasterWhisper | word timestamps CTranslate2 |
| ONNX-ASR | timestamped result модели |
| OpenVINO | word-level timestamps WhisperPipeline |
Грубая подстановка метки на весь сегмент распознавания запрещена.
Пайплайн и время жизни
После prescan и только при наличии файлов для обработки загружаются ASR-модель и один batch-owned диаризатор. До первого ASR проверяются доступность пословных таймкодов, модели диаризации и возможность создать диаризатор. Ошибка этого этапа останавливает весь запуск без частичных транскриптов.
Каждый файл обрабатывается последовательно:
- ASR;
- диаризация, если ASR нашёл речь;
- сведение слов с разметкой говорящих;
- форматирование и запись Markdown.
Один диаризатор последовательно переиспользуется для всех файлов батча. Данные
конкретной записи не становятся состоянием следующей. Объект освобождается при
завершении команды и не переносится через TranscribeFileResult.
Разметка говорящих хранится только до сведения. Единственный постоянный продуктовый артефакт — Markdown-транскрипт; локальный кеш файлов моделей живёт по существующим правилам загрузчиков.
Конфигурация диаризации
Автоматический режим использует:
- Pyannote segmentation 3.0;
- WeSpeaker ResNet34 LM;
- порог кластеризации 0,89;
- автоматическое число кластеров.
--speakers N передаёт явное число кластеров вместо автоматического. Для
предупреждения используется диагностическая граница из калибровки: малым
считается кластер с речью короче максимума из 5 секунд и 2% длительности записи.
Граница влияет только на предупреждение — кластер не отбрасывается, получает
обычный номер и не меняет статус команды.
Формат Markdown
При двух и более найденных кластерах тело состоит из линейных реплик:
[09:07] Speaker 1: Мы же у них не разворачиваемся…
[09:18] Speaker 2: Мне гораздо проще накатывать обновления…
- Печатается только начало реплики; доли секунды отбрасываются, а не округляются
(
09:07.96→[09:07]). Для записей длиннее часа используется[HH:MM:SS], иначе[MM:SS]. - Метка
Speaker Nне получает Markdown-выделение. - Нумерация начинается заново для каждого файла; номера назначаются по порядку первого появления кластера в словах транскрипта.
- Смена говорящего всегда начинает новую реплику.
- Речь одного говорящего дополнительно разбивается по паузе не меньше 2 секунд и максимальной длительности реплики 60 секунд.
- Слова без назначенного кластера группируются под
Speaker ?. - Перекрывающаяся речь остаётся в хронологическом порядке без особого синтаксиса.
- В шапку добавляется число голосовых кластеров и предупреждения. Таблица длительности по кластерам не выводится.
Без успешной разметки нескольких говорящих сохраняется нынешний формат обычного транскрипта с диапазонами времени.
Деградация и статус команды
| Ситуация | Артефакт | Консоль и шапка | Статус |
|---|---|---|---|
| Диаризация не запрошена | Обычный транскрипт | Без новых сообщений | Текущий |
| ASR не нашёл речь | Текущий пустой Markdown | Речь не обнаружена; диаризация не запускалась | 0 |
| Найдено не меньше двух кластеров | Транскрипт с Speaker N |
Число кластеров и предупреждения | 0, если нет иной ошибки |
| Найден один кластер | Обычный транскрипт без Speaker 1 |
Причина в консоли и шапке | Ненулевой |
| Есть слова без пересечения | Транскрипт с Speaker ? |
Число таких слов | 0 |
| Есть малый кластер | Транскрипт со всеми кластерами | Длительность малого кластера | 0 |
| Разметка пуста при непустом ASR | Обычный транскрипт | Явное предупреждение | Ненулевой |
| Ошибка диаризации конкретного файла | Обычный транскрипт | Явное предупреждение | Ненулевой |
| Нет пословных таймкодов или не инициализировался диаризатор | Файлы не обрабатываются | Понятная ошибка до ASR | Ненулевой |
В батче деградированный файл записывается, учитывается как неуспешная диаризация, а остальные файлы продолжают обрабатываться. Итоговый статус батча ненулевой, если хотя бы один файл деградировал или завершился ошибкой.
Критерии приёмки
Автоматические проверки
- Адаптер каждого ASR-бэкенда возвращает монотонные слова с временной привязкой; сборка слов сохраняет текст сегментов с точностью до пробелов.
- Сведение покрывает смену говорящего, отсутствие пересечения, равное
наибольшее перекрытие с результатом
Speaker ?, пунктуацию на границе реплик и хронологический порядок. - Форматтер проверяется для обычных, часовых, неизвестных и малых кластеров,
Speaker ?, отбрасывания долей таймкода, паузы 2 секунды и предела 60 секунд. - CLI проверяет несовместимые и граничные значения, не запускает ASR при ошибке preflight и соблюдает всю матрицу деградации в single- и batch-режимах.
- Батч создаёт диаризатор ровно один раз, пропускает его для пустого ASR, переиспользует между файлами и не пишет промежуточный кеш.
--threads,--verboseи--forceсохраняют описанную семантику.
Все автоматические тесты мокают движки и не скачивают реальные модели.
Ручная проверка
Финальная сборка прогоняется на трёх записях из отчётов карты:
- текст до и после сведения совпадает с точностью до переносов и пробелов;
- на плотном диалоге вручную проверяются устойчивость «голос → кластер», смены говорящего, пропуски, малый остаточный кластер и перекрывающаяся речь;
- автоматическая конфигурация воспроизводит наблюдённую форму результата: три основных и один малый остаточный кластер на Data Test, по два кластера на T2 BDMA и Yantar;
- последовательный прогон на доступном Intel baseline остаётся быстрее реального времени; фактические wall time и peak RSS записываются рядом с результатом проверки.
Документация
README должен описать новые CLI-флаги, ленивую загрузку моделей, ожидаемую
стоимость, формат Speaker N, предупреждения и batch-поведение. Направления
«Диаризация» и «Ручка нарезки абзацев» удаляются из backlog: первое перешло в
эту спецификацию, второе закрыто разрывом реплики на смене говорящего.
После стабилизации отдельно рассматриваются параллельный запуск и hardware-aware default.