Задача: Собрать управляемый TTS-пайплайн для учебных слогов и слов

Собрать управляемый TTS-пайплайн для учебных слогов и слов

Настроить собственный контролируемый TTS-процесс и заранее генерировать аудио для букв, слогов и слов вместо зависимости от непредсказуемого браузерного SpeechSynthesis.

Контекст

Связанная задача к браузерной озвучке cmu326hnm0bbpqw0qh5fgsv2f.

Эксперименты показали, что SpeechSynthesisUtterance приемлемо произносит многие целые слова, но плохо и непредсказуемо работает с отдельными буквами, короткими слогами и искусственно вырезанными частями слов.

Наблюдаемые примеры:

  • Собака — нормально;
  • Со — звучит примерно как С;
  • Р — ближе к Э;
  • Ры — нормально;
  • Свинь — может разваливаться на чтение названий букв;
  • Пель — нормально;
  • Ковь, Солн — могут читаться по буквам;
  • Ко → примерно Ка;
  • Ар → примерно А;
  • Ре → примерно Э;
  • ДеДэ.

Вывод: браузерный TTS нельзя считать надёжным источником педагогически корректного произношения для механики буква → слог → слово.


Цель

Собрать собственный управляемый TTS-пайплайн, через который заранее генерировать и проверять учебное аудио.

Основная идея:

контент карточки
буквы / слоги / слова
контролируемый TTS
ручная/автоматическая проверка
готовые аудиофайлы
приложение только воспроизводит заранее подготовленный звук

В рантайме учебного приложения не полагаться на системный голос пользователя для критичного произношения.


Что нужно генерировать

Минимум:

  • отдельные буквы, где это педагогически уместно;
  • учебные слоги;
  • отдельные слова к карточкам с картинками;
  • при необходимости короткие инструкции/реплики персонажей.

Особенно важно заранее генерировать все слоги и слова, которые реально используются в статическом учебном контенте.

Не нужен универсальный генератор всех возможных комбинаций русского языка. Генерируем только тот словарь, который реально входит в приложение.


Требования к TTS

Нужен движок/сервис, где можно лучше контролировать произношение, чем в браузерном SpeechSynthesis.

Желательные возможности:

  • стабильный голос между генерациями;
  • контроль языка ru-RU;
  • контроль rate;
  • контроль pitch, если поддерживается;
  • SSML или аналогичный механизм управления произношением;
  • возможность задавать паузы;
  • возможность влиять на чтение отдельных букв/слогов;
  • экспорт результата в WAV/MP3/OGG;
  • воспроизводимый результат при пакетной генерации.

Если конкретный TTS плохо читает отдельный слог, должна быть возможность задавать специальную TTS-строку отдельно от отображаемого текста.

Например:

type PronunciationAsset = {
  text: string
  ttsText?: string
  audioSrc: string
}

где:

{
  text: 'КО',
  ttsText: '<специальная строка/SSML для нужного произношения>',
  audioSrc: '/audio/syllables/ko.mp3',
}

Пайплайн контента

Предусмотреть реестр генерируемых единиц:

type TtsSourceItem = {
  id: string
  text: string
  kind: 'letter' | 'syllable' | 'word'
  ttsText?: string
  voiceId?: string
  rate?: number
  pitch?: number
}

Пример:

const items: TtsSourceItem[] = [
  {
    id: 'word-dog',
    text: 'СОБАКА',
    kind: 'word',
  },
  {
    id: 'syllable-so',
    text: 'СО',
    kind: 'syllable',
    ttsText: '...',
  },
  {
    id: 'letter-r',
    text: 'Р',
    kind: 'letter',
    ttsText: '...',
  },
]

Дальше отдельный script/build-step:

items
→ TTS API
→ audio files
→ manifest

Manifest готового аудио

После генерации приложение должно работать уже не с TTS, а с готовыми asset'ами.

Например:

type AudioAsset = {
  id: string
  text: string
  kind: 'letter' | 'syllable' | 'word'
  src: string
}
export const audioAssets: AudioAsset[] = [
  {
    id: 'word-dog',
    text: 'СОБАКА',
    kind: 'word',
    src: '/audio/words/sobaka.mp3',
  },
  {
    id: 'syllable-so',
    text: 'СО',
    kind: 'syllable',
    src: '/audio/syllables/so.mp3',
  },
]

В UI:

const audio = new Audio(asset.src)
audio.play()

Важная архитектурная идея

Разделить три слоя:

Display text
TTS input
Generated audio asset

Это позволит показывать ребёнку СО, но отправлять в TTS другую техническую строку/SSML, если только так удаётся получить правильное произношение.

То есть не делать предположение:

что написано на экране
=
что нужно буквально передать TTS

Проверка качества

Для каждой единицы нужен простой статус проверки:

type AudioReviewStatus =
  | 'generated'
  | 'approved'
  | 'rejected'

Минимальный workflow:

  1. сгенерировать пачку;
  2. прослушать;
  3. отметить плохие варианты;
  4. подобрать ttsText / voice / параметры;
  5. перегенерировать только отклонённые;
  6. после approved использовать asset в приложении.

Особенно внимательно проверять:

  • отдельные согласные;
  • двухбуквенные слоги;
  • слоги с ь/ъ;
  • обрезанные части слов;
  • сочетания, которые TTS может принять за аббревиатуры.

Связь с персонажами

Система голосовых персонажей может использовать тот же пайплайн.

Если персонажи должны отличаться голосом/темпом/высотой, для каждого персонажа можно либо:

  • генерировать отдельный комплект asset'ов;
  • либо использовать персонажей только для некритичных реплик, а учебные буквы/слоги оставить в одном эталонном голосе.

Это нужно решить отдельно после оценки объёма generated assets.


Первый практический этап

Не выбирать сразу окончательный TTS.

Сначала сравнить несколько кандидатов на коротком тестовом наборе проблемных строк:

Р
СО
РЫ
РЕ
ДЕ
КО
АР
СВИНЬ
ПЕЛЬ
КОВЬ
СОЛН
СОБАКА
СВИНЬЯ

Для каждого кандидата оценить:

  • корректность произношения;
  • стабильность;
  • наличие SSML/phoneme hints;
  • качество русского голоса;
  • возможность пакетной генерации;
  • стоимость;
  • лицензионные ограничения;
  • удобство сохранения результата в аудиофайлы.

После этого выбрать основной TTS и уже строить production pipeline.

Критерий готовности

Есть воспроизводимый процесс, который из статического списка учебных букв/слогов/слов генерирует проверенные аудиофайлы, сохраняет их как assets приложения и позволяет отдельно переопределять техническую TTS-строку для проблемных случаев.