Материалы / 12 минут
Добавить потоковую озвучку, которую можно немедленно остановить и безопасно заменить новым ответом.
Озвучивайте смысловыми фрагментами
Не ждите завершения длинного ответа. Передавайте в TTS законченную фразу или небольшой смысловой блок, сохраняя порядок сегментов.
Слишком короткие куски делают голос рваным, слишком длинные увеличивают время первого звука. Размер сегмента подбирается по реальному latency TTS.
Прерывание является штатным сценарием
Новый голос пользователя должен отменить генерацию текста, текущий TTS-запрос, очередь аудио и уже играющий источник. Одной кнопки pause недостаточно.
Каждый turn получает идентификатор. Поздний ответ старого turn игнорируется и не может снова запустить воспроизведение.
Управляйте очередью явно
Храните состояния idle, synthesizing, playing и interrupted. Между фрагментами не должно возникать гонки за AudioContext.
После ошибки синтеза текст остаётся доступным. Голос — дополнительный канал, а не единственный способ получить ответ.
let turn: AbortController | null = null;
function startTurn() {
turn?.abort();
stopAudioQueue();
turn = new AbortController();
return turn.signal;
}
function interrupt() {
turn?.abort();
stopAudioQueue();
}