diff --git a/CONTEXT.md b/CONTEXT.md index 7ac5ae0..9e227e3 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -33,7 +33,7 @@ _Avoid_: Токен, ASR-сегмент _Avoid_: Результат диаризации, сегменты говорящих **Голосовой кластер**: -Анонимная группа интервалов разметки говорящих, которые диаризатор относит к одному голосу. Не равен подтверждённому участнику встречи: ложный или малый кластер сохраняет отдельную метку. +Анонимная группа интервалов разметки говорящих, которые диаризатор относит к одному голосу. Не обязательно соответствует реальному участнику встречи: диаризация может создать ложный или малый кластер. _Avoid_: Участник, человек **Реплика говорящего**: diff --git a/docs/adr/007-word-level-speaker-diarization.md b/docs/adr/007-word-level-speaker-diarization.md index 0d94fef..6e2d2dc 100644 --- a/docs/adr/007-word-level-speaker-diarization.md +++ b/docs/adr/007-word-level-speaker-diarization.md @@ -28,6 +28,12 @@ WeSpeaker ResNet34 LM проверена на трёх записях с изв 19,1 секунды; поэтому малые кластеры нельзя молча отбрасывать, а разметку нельзя считать эталоном точных границ и перекрывающейся речи. +Двуязычная CAMPPlus zh/en оказалась примерно на 30% быстрее и при известном +числе участников улучшила прокси-метрику на двух записях, но для неё не нашлось +общего автоматического порога без лишних кластеров или склейки реальных голосов. +Поэтому она остаётся кандидатом только для будущего режима с обязательным +явным числом участников, а не для первой версии. + На доступном слабом Intel baseline, Core i7-6820HQ с урезанным питанием, последовательные ASR и диаризация обработали час записи примерно за 23 минуты. Диаризация увеличивает полное время примерно в 2,4 раза, но остаётся быстрее @@ -54,18 +60,14 @@ ASR-бэкенд приводит свой результат к общему н объединяет соседние слова одного говорящего в реплики. Распознавание по-прежнему выполняется на полных сегментах и сохраняет контекст модели. -Первая реализация последовательна на всех устройствах: ASR, диаризация, -сведение, Markdown. В батче один диаризатор создаётся после prescan, -переиспользуется для всех файлов и освобождается вместе с командой. Разметка -говорящих живёт только в памяти текущего запуска; постоянного кеша результата -нет. - -Грубого fallback на целый сегмент и автоматического переключения устройства -нет. Отсутствие пословных таймкодов или ошибка инициализации диаризатора -останавливают запуск до ASR. Ошибка диаризации конкретного файла после успешного -ASR не уничтожает полезный результат: сохраняется обычный транскрипт с явным -предупреждением и ненулевым статусом, а батч продолжает остальные файлы. -Подробная матрица поведения находится в +Диаризация не вводит грубый fallback на целый сегмент и не переключает +устройство ASR ради получения пословных таймкодов. Существующий GPU→CPU fallback +распознавания сохраняется и завершается до диаризации. Отсутствие пословных +таймкодов или ошибка инициализации диаризатора останавливают запуск до ASR. +Ошибка диаризации конкретного файла после успешного ASR не уничтожает полезный +результат: сохраняется обычный транскрипт с явным предупреждением и ненулевым +статусом, а батч продолжает остальные файлы. Порядок первой реализации, время +жизни диаризатора, кеш и подробная матрица поведения находятся в [спецификации](../specs/2026-08-14-speaker-diarization.md). ## Последствия diff --git a/docs/specs/2026-08-14-speaker-diarization.md b/docs/specs/2026-08-14-speaker-diarization.md index 3171d99..832b349 100644 --- a/docs/specs/2026-08-14-speaker-diarization.md +++ b/docs/specs/2026-08-14-speaker-diarization.md @@ -57,13 +57,15 @@ слова нормализуются в адаптере бэкенда; их обратная сборка должна сохранять распознанный текст с точностью до нормализации пробелов. -Результат диаризации — отдельная упорядоченная разметка говорящих: временные -интервалы с анонимным идентификатором голосового кластера. ASR-бэкенд не знает о -кластерах, а диаризатор не знает о распознанном тексте. +Разметка говорящих хранится отдельно от результата ASR: это упорядоченные +временные интервалы с анонимным идентификатором голосового кластера. ASR-бэкенд +не знает о кластерах, а диаризатор не знает о распознанном тексте. -Операция сведения назначает слову кластер с наибольшим временным перекрытием. -Если пересечения нет либо наибольшее перекрытие не единственно, слово получает -неизвестного говорящего. Соседние слова одного говорящего объединяются в +Операция сведения суммирует временное перекрытие слова с интервалами каждого +кластера и назначает кластер с единственным наибольшим ненулевым перекрытием. +Если пересечения нет либо несколько кластеров делят наибольшее значение, слово +получает неизвестного говорящего: порядок кластеров не используется как +искусственная развязка ничьей. Соседние слова одного говорящего объединяются в реплику; порядок слов и исходная временная шкала не меняются. Все три ASR-пути обязаны предоставлять пословный контракт до включения @@ -105,12 +107,14 @@ - Pyannote segmentation 3.0; - WeSpeaker ResNet34 LM; -- `FastClusteringConfig.threshold = 0.89`; +- порог кластеризации 0,89; - автоматическое число кластеров. -`--speakers N` передаёт явное число кластеров вместо автоматического. Малый -кластер — кластер с речью короче максимума из 5 секунд и 2% длительности записи. -Он не отбрасывается и получает обычный номер, но вызывает предупреждение. +`--speakers N` передаёт явное число кластеров вместо автоматического. Для +предупреждения используется диагностическая граница из калибровки: малым +считается кластер с речью короче максимума из 5 секунд и 2% длительности записи. +Граница влияет только на предупреждение — кластер не отбрасывается, получает +обычный номер и не меняет статус команды. ## Формат Markdown @@ -122,8 +126,9 @@ [09:18] Speaker 2: Мне гораздо проще накатывать обновления… ``` -- Печатается только начало реплики, округлённое до целой секунды. Для записей - длиннее часа используется `[HH:MM:SS]`, иначе `[MM:SS]`. +- Печатается только начало реплики; доли секунды отбрасываются, а не округляются + (`09:07.96` → `[09:07]`). Для записей длиннее часа используется + `[HH:MM:SS]`, иначе `[MM:SS]`. - Метка `Speaker N` не получает Markdown-выделение. - Нумерация начинается заново для каждого файла; номера назначаются по порядку первого появления кластера в словах транскрипта. @@ -164,9 +169,10 @@ - Адаптер каждого ASR-бэкенда возвращает монотонные слова с временной привязкой; сборка слов сохраняет текст сегментов с точностью до пробелов. - Сведение покрывает смену говорящего, отсутствие пересечения, равное - перекрытие, пунктуацию на границе реплик и хронологический порядок. + наибольшее перекрытие с результатом `Speaker ?`, пунктуацию на границе реплик + и хронологический порядок. - Форматтер проверяется для обычных, часовых, неизвестных и малых кластеров, - `Speaker ?`, паузы 2 секунды и предела 60 секунд. + `Speaker ?`, отбрасывания долей таймкода, паузы 2 секунды и предела 60 секунд. - CLI проверяет несовместимые и граничные значения, не запускает ASR при ошибке preflight и соблюдает всю матрицу деградации в single- и batch-режимах. - Батч создаёт диаризатор ровно один раз, пропускает его для пустого ASR,