Голосовая модель выдаёт аудио, а для телефонного звонка этого мало. Между моделью и звонящим агент обрезает тишину в начале каждой фразы, меняет её частоту дискретизации, проверяет её обратным распознаванием и кэширует, а ночью кэш проверяет себя заново. Эта заметка описывает такую обработку.
У синтезированной фразы может быть собственная тишина в начале, которую не показывает ни один лог времени. Эта заметка начинается с неё.
Измерено на: ведущая тишина по 400 клипам из голосового кэша, порог −50 дБFS. Доли кэша: стенд нагрузочного тестирования, агент-рекрутер, 64 192 фразы. Пороги проверок соответствуют значениям по умолчанию в продакшене и настраиваются для каждой установки.
Коротко: тишина перед первым словом сокращается с медианных 280 мс до 40 мс. Каждый клип, попадающий в кэш, распознаётся обратно и сравнивается с текстом, который он должен был произнести. Кэш перепроверяет себя каждую ночь, пока нет звонков. На стенде нагрузочного тестирования 94% первых фраз ответа брались из проверенного кэша, а фраза из кэша начинается примерно через 1 мс.
От аудио до ответа в звонке
Модель синтеза речи превращает текст в аудио. Она не создавалась для телефонной линии, и разрыв проявляется в мелочах, которые звонящий замечает сразу:
- Тишина перед первым словом. Каждый клип начинается с короткой паузы. Звонящему кажется, что агент замялся.
- Пауза внутри фразы. На телефонной линии полсекунды тишины посреди фразы звучат как обрыв связи. Звонящий начинает говорить в этот провал, и реплика ломается.
- Оборванная фраза или фраза, которая не кончается. Изредка модель останавливается на полпути или зацикливается.
- Не те слова. Любой нейронный голос иногда может произнести не тот текст, который ему дали, поэтому каждый клип проверяется. Все акустические проверки проходят: это чистая речь, но другая фраза.
- Щелчки и клиппинг. Аудио, созданное с одной частотой дискретизации, должно дойти до линии с другой, по кускам и без щелчка на каждом стыке.
Это и есть расстояние между аудио и ответом в звонке, и ни одно из этих явлений не вина модели. Dialogist закрывает это расстояние обработкой на выходе, проверкой каждого клипа и кэшем, который сам следит за своей чистотой.
Тишина перед первым словом
Мы измерили начало 400 клипов из голосового кэша. Медианный клип начинался с 280 мс тишины, и ни один не начинался раньше 200 мс. Эта тишина находится ровно между концом вопроса звонящего и ответом агента.
Агент обрезает её во время воспроизведения клипа:
- Кадры. Обрезчик читает аудио кадрами по 10 мс. Первый кадр громче −50 дБFS считается началом речи.
- Запас. Воспроизведение начинается за 40 мс до этого кадра. Сорок миллисекунд сохраняют мягкое начало первого звука, поэтому ничего не срезается.
- Потоковая работа. Обрезчик задерживает только тихие кадры, а всё, что идёт с начала речи, пропускает байт в байт.
- Предел. Если речь не появилась за 600 мс, обрезчик воспроизводит клип как есть: пауза обходится дешевле, чем проглоченное первое слово.
- Оригинал остаётся. Кэш хранит необрезанный клип. Обрезка происходит при воспроизведении, поэтому мы можем настраивать её, не трогая сохранённый файл.
По умолчанию агент обрезает первую фразу каждого ответа: там тишина означает просто ожидание. Паузы между следующими фразами остаются такими, какими их сделал голос, потому что там они звучат как дыхание.
Обрезка убирает около 240 мс из медианных 280 мс вступления. В линии ответ одного звонка пришёл примерно на 200 мс раньше.
Частота дискретизации без щелчков
Голос создаётся с частотой дискретизации студийного уровня, а телефонная линия работает на 8 или 16 кГц. Преобразовать клип целиком просто. Щелчки появляются при преобразовании потока по кускам: каждый кусок, преобразованный отдельно, начинается и заканчивается небольшим переходным всплеском, и на стыках он слышен.
Агент преобразует методом overlap-save. Он фильтрует каждый кусок с контекстом по обе стороны и отправляет только середину, ту часть, которая посчитана с полным контекстом. При такой потоковой передаче результат совпадает с преобразованием всего клипа целиком с точностью до 2 младших разрядов, а это ниже всего, что может передать телефонная линия.
Каждый клип проверяется
Прежде чем клип попадёт в кэш, где его услышат многие звонящие, агент его проверяет. Проверка прогоняет аудио обратно через распознавание речи и через набор акустических тестов.
| Проверка | Не проходит, если | Зачем |
|---|---|---|
| Обратное распознавание | распознанный текст совпадает с задуманным меньше чем на 80% | Единственный способ узнать, что голос произнёс именно эту фразу. Беглый клип с другими словами проходит все остальные тесты. |
| Длина | клип короче 0,4× или длиннее 2,5× от длины, ожидаемой по тексту | Слишком короткий выявляет оборванную фразу. Слишком длинный выявляет зацикливание. |
| Пауза внутри | любая тишина внутри фразы длиннее 0,7 с | На телефонной линии это звучит как обрыв связи. |
| Уровень | клип в целом тише −50 дБFS | Пустой или почти беззвучный клип. |
| Клиппинг | больше 0,5% отсчётов достигают полной шкалы | Искажение, которое звонящий слышит как треск. |
| Края | тишина в начале или в конце длиннее 0,5 с | Только предупреждение: сама речь верна. |
Две детали делают проверку справедливой:
- Числа оцениваются мягко. Распознавание записывает «500» словами, поэтому посимвольное сравнение забраковало бы безупречный клип. Для текста с цифрами расхождение даёт предупреждение, и агент не запускает бесконечную перегенерацию клипа.
- Знаки произношения убираются перед сравнением, поэтому знак ударения в тексте не считается ошибкой.
Клип, не прошедший проверку, агент генерирует заново. Если он снова не проходит, агент помечает его для прослушивания человеком.
Фразы, готовые до звонка
Многое из того, что говорит агент, предсказуемо: приветствие, вопросы из сценария, подтверждения. Мы прогреваем кэш агента до начала звонков: запускаем с агентом имитационные разговоры, собираем сказанное, синтезируем каждую фразу, проверяем её так, как описано выше, и сохраняем.
Если фраза не проходит проверку, она получает вторую попытку, а всё, что по-прежнему не дотягивает до планки, помечается в отчёте.
На стенде нагрузочного тестирования из кэша брались 94% первых фраз ответа и 95% всех 64 192 фраз. Фраза из кэша начинается примерно через миллисекунду, свежесинтезированная примерно через 100 мс.
Ночью кэш чистится сам
Кэш не лучше своего худшего клипа, поэтому Dialogist перепроверяет его в нерабочее время.
- Когда. В ночное окно, по умолчанию с 01:00 до 06:00, и только пока нет звонков. Если звонок приходит, проверка приостанавливается и смотрит снова через минуту.
- Что. Клипы, которые ни разу не проверялись, клипы, прошедшие с предупреждением, и клипы, проверенные больше 30 дней назад.
- В каком порядке. Сначала самые проигрываемые. Ошибка во фразе, которую слышат тысячу раз в день, обходится дороже, чем в фразе, которую услышали один раз.
- Сколько. До 2000 клипов за ночь, по одному, чтобы проверка не конкурировала с наступающим утром.
- На каком языке. Проверка распознаёт каждый клип на том языке, для которого он создан, и поэтому не забракует по ошибке английскую фразу в преимущественно сербском кэше.
- Если проверка не пройдена. Проверка перегенерирует клип, до двух раз. Новое аудио заменяет старое в той же записи, а запись сохраняет историю воспроизведений.
- Карантин. Если перегенерация не исправляет клип, проверка помещает его в карантин. Агент никогда не воспроизводит клип из карантина: он синтезирует эту фразу на лету, и живой результат не может перезаписать файл в карантине. Клип остаётся, пока человек не прослушает его и не одобрит, не перегенерирует или не удалит.
Каждый ночной запуск оставляет однострочный отчёт: сколько клипов проверено, прошло, перегенерировано и помещено в карантин.
Одна фраза, один звук
Кэш хранит каждый клип вместе со всем, что влияет на его звучание: голосом, темпом речи, языком и профилем произношения. Два агента с одним голосом и разным темпом никогда не делят клип.
Словари произношения (названия брендов, улицы, жаргон) тоже хранятся вместе с клипом. Когда ночная проверка перегенерирует фразу, она применяет те же записи словаря, что и исходный звонок, поэтому новый клип звучит так же, как заменяемый.
На линии
Последний шаг: микшер, который отправляет аудио звонящему.
- Мягкий лимитер на уровне −1 дБFS на сумме всего, что воспроизводится, чтобы голос агента и любой фоновый звук не клиппировали вместе.
- Затухание за 30 мс, когда агент останавливается из-за перебивания, чтобы остановка не давала щелчка.
- Просадка голоса агента, пока звонящий говорит; голос возвращается, когда звонящий замолкает. О том, как агент обрабатывает речь звонящего, рассказывает заметка Слушать, пока говоришь.