Files
local-transcriber/docs/adr/007-word-level-speaker-diarization.md
T
Dmitriy Dementiev b8333ba583 docs(diarization): зафиксированы ADR и спецификация
- Зачем:
  - решения карты должны стать устойчивой основой для реализации диаризации.
- Что:
  - добавлены ADR-007 и спецификация пословной диаризации.
  - дополнен доменный словарь и удалены закрытые направления из backlog.
- Проверка:
  - git diff --cached --check.
2026-08-14 15:55:25 +03:00

8.9 KiB

ADR-007: Пословная диаризация через sherpa-onnx

Статус: Принято Дата: 2026-08-14

Контекст

Разделение говорящих — главный структурный разрыв между локальным транскриптом и облачными сервисами в сценарии подготовки конспектов и протоколов встреч. Диаризация при этом не является ещё одним движком распознавания: она независимо строит разметку говорящих, которую затем нужно свести с результатом ASR.

Привязка одного говорящего ко всему сегменту распознавания оказалась слишком грубой. На трёх русскоязычных рабочих созвонах чужая реплика не короче секунды встретилась в 6–7% сегментов разговоров на двоих и в 27% сегментов встречи втроём. Сегменты распознавания проходят по тишине, а не по смене говорящего, поэтому сохранить контекст RNN-T и получить реплики можно только через более мелкую единицу сведения.

Эксперимент

Локальная связка sherpa-onnx с сегментацией Pyannote 3.0 и эмбеддингами WeSpeaker ResNet34 LM проверена на трёх записях с известным составом. Для автоматического определения числа голосовых кластеров выбран порог 0,89: это единственное проверенное значение, которое на трёх контрольных фрагментах дало 3 / 2 / 2 кластера. На полной встрече втроём остался ложный кластер длительностью 19,1 секунды; поэтому малые кластеры нельзя молча отбрасывать, а разметку нельзя считать эталоном точных границ и перекрывающейся речи.

На доступном слабом Intel baseline, Core i7-6820HQ с урезанным питанием, последовательные ASR и диаризация обработали час записи примерно за 23 минуты. Диаризация увеличивает полное время примерно в 2,4 раза, но остаётся быстрее реального времени и приемлема как явно включаемая функция. Конкретный Core i5 11-го поколения не проверен, поскольку такого устройства нет.

Исходные данные и ограничения зафиксированы в отчётах о калибровке, смешении говорящих и производительности на Intel.

Решение

Диаризацию реализуем как явно включаемый пост-процессинг через sherpa-onnx. Первая версия использует Pyannote segmentation 3.0, WeSpeaker ResNet34 LM, порог кластеризации 0,89 и автоматическое число кластеров; известное число участников можно передать явно.

Говорящий назначается слову с временной привязкой, а не сегменту распознавания. Каждый ASR-бэкенд приводит свой результат к общему набору слов с положением на временной шкале. Проходы ASR и диаризации независимо получают одно аудио, после чего отдельная операция сводит слова с интервалами разметки говорящих и объединяет соседние слова одного говорящего в реплики. Распознавание по-прежнему выполняется на полных сегментах и сохраняет контекст модели.

Первая реализация последовательна на всех устройствах: ASR, диаризация, сведение, Markdown. В батче один диаризатор создаётся после prescan, переиспользуется для всех файлов и освобождается вместе с командой. Разметка говорящих живёт только в памяти текущего запуска; постоянного кеша результата нет.

Грубого fallback на целый сегмент и автоматического переключения устройства нет. Отсутствие пословных таймкодов или ошибка инициализации диаризатора останавливают запуск до ASR. Ошибка диаризации конкретного файла после успешного ASR не уничтожает полезный результат: сохраняется обычный транскрипт с явным предупреждением и ненулевым статусом, а батч продолжает остальные файлы. Подробная матрица поведения находится в спецификации.

Последствия

  • Общий контракт результата распознавания расширяется каноническими словами с временной привязкой; сегменты распознавания сохраняются для совместимости и контроля качества.
  • FasterWhisper, ONNX-ASR и OpenVINO должны экспортировать один и тот же пословный контракт. OpenVINO GenAI 2026.x уже предоставляет нужные таймкоды, поэтому ограничение находится в адаптере проекта, а не в движке.
  • sherpa-onnx становится обычной runtime-зависимостью, а две модели диаризации скачиваются и кешируются лениво при первом запросе.
  • Выход остаётся линейным Markdown с анонимными метками Speaker N. Сопоставление голосов с именами и специальная запись перекрывающейся речи не входят в ядро CLI.
  • Последовательный режим задаёт корректный baseline. Параллельный запуск и автоматическое включение на мощных устройствах требуют отдельных измерений после стабилизации.

Отклонённые альтернативы

Альтернатива Почему отклонена
Не делать диаризацию Оставляет главный продуктовый разрыв, хотя измеренная стоимость допустима для явной функции
Мажоритарный говорящий на весь сегмент распознавания Теряет чужие реплики на всех трёх проверенных записях
Сначала диаризация, затем ASR коротких интервалов Лишает RNN-T длинного контекста и ухудшает согласование и пунктуацию
pyannote.audio Тянет PyTorch и требует Hugging Face token с принятием лицензии
Сборка поверх приватных деталей onnx-asr Экономит небольшую отдельную зависимость ценой нестабильного внутреннего API и собственной кластеризации
Параллельные проходы в первой версии Нет прямого benchmark и измеренного общего пика памяти; сначала нужен корректный последовательный baseline