Задача: Добавить браузерную озвучку букв, слогов и отдельных слов

Добавить браузерную озвучку букв, слогов и отдельных слов

Использовать Web Speech API для воспроизведения учебных единиц: букв, слогов и отдельных слов.

Цель

Добавить браузерную озвучку учебных единиц без отдельного TTS-бэкенда: букв, слогов и отдельных слов.

Основной сценарий:

  1. Ребёнок видит букву, слог или слово.
  2. Нажимает кнопку воспроизведения.
  3. Браузер произносит соответствующий текст.

На первом этапе использовать встроенный Web Speech API браузера.


Основное API

const utterance = new SpeechSynthesisUtterance('Собака')
utterance.lang = 'ru-RU'

window.speechSynthesis.speak(utterance)

Остановка текущей речи:

window.speechSynthesis.cancel()

Полезные параметры:

utterance.lang = 'ru-RU'
utterance.rate = 1
utterance.pitch = 1
utterance.volume = 1
  • lang — язык/локаль синтеза;
  • rate — скорость речи;
  • pitch — высота голоса;
  • volume — громкость 0..1;
  • voice — конкретный системный голос.

Выбор русского голоса

const voices = window.speechSynthesis.getVoices()

const russianVoice = voices.find(
  voice => voice.lang.toLowerCase().startsWith('ru'),
)

const utterance = new SpeechSynthesisUtterance('Рыба')
utterance.lang = 'ru-RU'
utterance.voice = russianVoice ?? null

window.speechSynthesis.speak(utterance)

Список голосов может загружаться асинхронно:

window.speechSynthesis.onvoiceschanged = () => {
  const voices = window.speechSynthesis.getVoices()
  console.log(voices)
}

Базовый helper

export type SpeakOptions = {
  lang?: string
  rate?: number
  pitch?: number
  volume?: number
  voice?: SpeechSynthesisVoice | null
}

export const speak = (
  text: string,
  options: SpeakOptions = {},
) => {
  window.speechSynthesis.cancel()

  const utterance = new SpeechSynthesisUtterance(text)

  utterance.lang = options.lang ?? 'ru-RU'
  utterance.rate = options.rate ?? 1
  utterance.pitch = options.pitch ?? 1
  utterance.volume = options.volume ?? 1

  if (options.voice) {
    utterance.voice = options.voice
  }

  window.speechSynthesis.speak(utterance)

  return utterance
}

Примеры:

speak('А')
speak('МА')
speak('Собака')

Рекомендуемый hook для React

import { useCallback, useEffect, useState } from 'react'

export const useSpeechSynthesis = () => {
  const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([])

  useEffect(() => {
    const loadVoices = () => {
      setVoices(window.speechSynthesis.getVoices())
    }

    loadVoices()
    window.speechSynthesis.addEventListener('voiceschanged', loadVoices)

    return () => {
      window.speechSynthesis.removeEventListener('voiceschanged', loadVoices)
    }
  }, [])

  const speak = useCallback((text: string) => {
    window.speechSynthesis.cancel()

    const utterance = new SpeechSynthesisUtterance(text)
    utterance.lang = 'ru-RU'

    const russianVoice = voices.find(
      voice => voice.lang.toLowerCase().startsWith('ru'),
    )

    if (russianVoice) {
      utterance.voice = russianVoice
    }

    window.speechSynthesis.speak(utterance)
  }, [voices])

  const stop = useCallback(() => {
    window.speechSynthesis.cancel()
  }, [])

  return {
    voices,
    speak,
    stop,
  }
}

Логика UI

Минимально нужны:

  • кнопка Прослушать;
  • повторное воспроизведение;
  • отмена предыдущей речи перед новым speak();
  • состояние speaking, если оно понадобится для анимации/disable кнопки;
  • fallback, если speechSynthesis недоступен.

События SpeechSynthesisUtterance, которые можно использовать:

utterance.onstart = () => {}
utterance.onend = () => {}
utterance.onerror = event => {}

Важные ограничения

  • качество и набор голосов зависят от браузера/ОС;
  • одна и та же строка может звучать по-разному на разных устройствах;
  • одиночные буквы могут произноситься не так, как ожидается педагогически — это нужно отдельно проверить на целевых браузерах;
  • API подходит для готовой озвучки, но не даёт напрямую PCM/AudioBuffer для анализа;
  • не смешивать эту задачу с экспериментами собственного синтезатора речи.

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

Буква, слог или отдельное слово передаются одним методом speak(text), корректно произносятся на русском языке, повторный запуск не наслаивается на предыдущий, ошибки и отсутствие API обрабатываются предсказуемо.

Ворклоги

Прогресс: ограничения и странности браузерного SpeechSynthesis

Проверена встроенная браузерная озвучка на отдельных словах, слогах и буквах. Для целых слов API в ряде случаев работает приемлемо, но на коротких слогах и отдельных буквах проявляются заметные и непредсказуемые ошибки интерпретации текста.

Что звучит нормально

  • Собака — произносится нормально.
  • Ры — произносится нормально.
  • Свинья — произносится нормально.
  • Пель — неожиданно произносится нормально.

Наблюдаемые сбои

  • Со — звучит примерно как просто С.
  • Р — звучит скорее как Э.
  • Ре — тоже звучит примерно как Э.
  • Свинь — вместо слога начинает читать как названия букв: примерно Эс Вэ Ен Мягкий знак. При этом И и Н отдельно не проговариваются ожидаемо, а часть последовательности интерпретируется как Ен.
  • Ковь — тоже разваливается на чтение по буквам.
  • Солн — также читается по буквам/не как слог.
  • Ко — звучит как Ка.
  • Ар — звучит как А.
  • Де — звучит как Дэ.

Основной вывод

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

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

Особенно проблемны:

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

Практическое следствие

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

Для целых слов его можно использовать напрямую, но для букв и слогов потребуется один из вариантов:

  1. ручные исключения / словарь альтернативных строк для конкретного TTS;
  2. предварительно записанные аудиофайлы;
  3. отдельный TTS/SSML-движок с более управляемым произношением;
  4. гибрид: слова через браузерный TTS, проблемные буквы/слоги — через подготовленное аудио.

Важно

Эти наблюдения относятся к фактическому поведению текущего браузерного/системного голоса. На другой ОС, браузере или другом SpeechSynthesisVoice результат может отличаться, поэтому подобные исключения нельзя считать универсальными для всех устройств.