Добавить браузерную озвучку букв, слогов и отдельных слов
Цель
Добавить браузерную озвучку учебных единиц без отдельного TTS-бэкенда: букв, слогов и отдельных слов.
Основной сценарий:
- Ребёнок видит букву, слог или слово.
- Нажимает кнопку воспроизведения.
- Браузер произносит соответствующий текст.
На первом этапе использовать встроенный 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 обрабатываются предсказуемо.