Использование Web Speech API
Web Speech API предоставляет две разные функциональные области — распознавание речи и синтез речи (также известный как текст в речь или tts), которые открывают интересные новые возможности для доступности и механизмов управления. Эта статья предоставляет простое введение в обе области, а также демонстрации.
Распознавание речи
Распознавание речи включает в себя получение речи через микрофон устройства, которая затем проверяется службой распознавания речи по списку грамматики (в основном, словарный запас, который вы хотите распознать в конкретном приложении). Когда слово или фраза успешно распознаются, они возвращаются в виде результата (или списка результатов) в виде текстовой строки, и по результатам могут быть инициированы дальнейшие действия.
Web Speech API имеет главный контроллер для этого — SpeechRecognition — плюс ряд тесно связанных интерфейсов для представления грамматики, результатов и т. д. Как правило, для распознавания речи используется стандартная система распознавания речи, доступная на устройстве — большинство современных операционных систем имеют систему распознавания речи для выдачи голосовых команд. Подумайте о функции «Диктовка» в macOS, Siri в iOS, Cortana в Windows 10, Android Speech и т. д.
Примечание: В некоторых браузерах, таких как Chrome, использование распознавания речи на веб-странице включает в себя серверный движок распознавания. Ваш аудиозапись отправляется на веб-сервис для обработки распознавания, поэтому он не будет работать автономно.
Демо
Чтобы продемонстрировать простое использование распознавания речи Web Speech, мы написали демонстрацию под названием Смена цвета с помощью речи. При нажатии/щелчке по экрану вы можете произнести ключевое слово HTML-цвета, и цвет фона приложения изменится на этот цвет.
Чтобы запустить демонстрацию, перейдите по ссылке на демонстрацию в поддерживаемом мобильном браузере (например, Chrome).
HTML и CSS
HTML и CSS для приложения очень просты. У нас есть заголовок, абзац с инструкциями и div, в который мы выводим диагностические сообщения.
<h1>Speech color changer</h1> <p>Tap/click then say a color to change the background color of the app.</p> <div> <p class="output"><em>…diagnostic messages</em></p> </div>
CSS предоставляет очень простую адаптивную стилизацию, чтобы приложение выглядело хорошо на разных устройствах.
JavaScript
Давайте рассмотрим JavaScript более подробно.
Префиксные свойства
Браузеры в настоящее время поддерживают распознавание речи с префиксными свойствами. Поэтому в начале нашего кода мы включаем эти строки, чтобы обеспечить поддержку как префиксных свойств, так и не префиксных версий, которые могут быть реализованы в будущем:
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const SpeechGrammarList = window.SpeechGrammarList || window.webkitSpeechGrammarList; const SpeechRecognitionEvent = window.SpeechRecognitionEvent || window.webkitSpeechRecognitionEvent;
Грамматика
В следующей части кода определяется грамматика, которую мы хотим распознавать нашему приложению. Следующая переменная определяет нашу грамматику:
const colors = [
"aqua",
"azure",
"beige",
"bisque",
"black",
"blue",
"brown",
"chocolate",
"coral" /* … */,
];
const grammar = `#JSGF V1.0; grammar colors; public <color> = ${colors.join(
" | ",
)};`;
Используемый формат грамматики — JSpeech Grammar Format (JSGF) — вы можете узнать больше об этом по ссылке на спецификацию. Однако пока давайте быстро пройдёмся по ней:
- Строки разделяются точкой с запятой, как и в JavaScript.
- Первая строка —
#JSGF V1.0;— указывает используемый формат и версию. Это всегда необходимо включать в первую очередь. - Вторая строка указывает тип термина, который мы хотим распознать.
publicобъявляет, что это общее правило, строка в угловых скобках определяет распознаваемое имя для этого термина (color), а список элементов после знака равенства — это альтернативные значения, которые будут распознаваться и приниматься как соответствующие значения для термина. Обратите внимание, как каждый из них разделяется символом «|». - Вы можете определить столько терминов, сколько хотите, на отдельных строках, следуя приведенной выше структуре, и включить довольно сложные определения грамматики. В этой базовой демонстрации мы упрощаем всё.
Включение грамматики в распознавание речи
Следующим шагом является определение экземпляра распознавания речи для управления распознаванием в нашем приложении. Это делается с помощью конструктора SpeechRecognition(). Мы также создаем новый список грамматики для хранения нашей грамматики, используя конструктор SpeechGrammarList().
const recognition = new SpeechRecognition(); const speechRecognitionList = new SpeechGrammarList();
Мы добавляем нашу grammar в список, используя метод SpeechGrammarList.addFromString(). Он принимает в качестве параметров строку, которую мы хотим добавить, а также (необязательно) значение веса, которое указывает важность этой грамматики по отношению к другим грамматикам, доступным в списке (может принимать значения от 0 до 1 включительно). Добавленая грамматика доступна в списке как объект SpeechGrammar.
speechRecognitionList.addFromString(grammar, 1);
Затем мы добавляем SpeechGrammarList в экземпляр распознавания речи, установив его в значение свойства SpeechRecognition.grammars. Мы также устанавливаем несколько других свойств экземпляра распознавания перед продолжением:
-
SpeechRecognition.continuous: Управляет тем, сохраняются ли непрерывные результаты (true), или только один результат каждый раз, когда начинается распознавание (false). -
SpeechRecognition.lang: Устанавливает язык распознавания. Установка этого значения является хорошей практикой и, следовательно, рекомендуется. -
SpeechRecognition.interimResults: Определяет, должна ли система распознавания речи возвращать промежуточные результаты или только окончательные. Окончательные результаты достаточно хороши для этой простой демонстрации. -
SpeechRecognition.maxAlternatives: Устанавливает количество альтернативных возможных совпадений, которые должны возвращаться на результат. Иногда это может быть полезно, скажем, если результат не совсем ясен, и вы хотите отобразить список альтернатив, чтобы пользователь мог выбрать правильный. Но это не нужно для этой простой демонстрации, поэтому мы просто указываем один (на самом деле это по умолчанию).
recognition.grammars = speechRecognitionList; recognition.continuous = false; recognition.lang = "en-US"; recognition.interimResults = false; recognition.maxAlternatives = 1;
Запуск распознавания речи
После получения ссылок на выходной <div> и элемент HTML (так что мы можем выводить диагностические сообщения и обновлять цвет фона приложения позже), мы реализуем обработчик onclick, чтобы при нажатии/щелчке на экран служба распознавания речи запускалась. Это достигается вызовом SpeechRecognition.start(). Метод forEach() используется для вывода цветных индикаторов, показывающих, какие цвета следует попробовать произнести.
const diagnostic = document.querySelector(".output");
const bg = document.querySelector("html");
const hints = document.querySelector(".hints");
let colorHTML = "";
colors.forEach((color, i) => {
console.log(color, i);
colorHTML += `<span style="background-color:${color};"> ${color} </span>`;
});
hints.innerHTML = `Tap or click then say a color to change the background color of the app. Try ${colorHTML}.`;
document.body.onclick = () => {
recognition.start();
console.log("Ready to receive a color command.");
};
Получение и обработка результатов
После запуска распознавания речи можно использовать много обработчиков событий для извлечения результатов и других фрагментов связанной информации (см. события SpeechRecognition). Наиболее часто используемым, вероятно, будет событие result, которое срабатывает после получения успешного результата:
recognition.onresult = (event) => {
const color = event.results[0][0].transcript;
diagnostic.textContent = `Result received: ${color}.`;
bg.style.backgroundColor = color;
console.log(`Confidence: ${event.results[0][0].confidence}`);
};
Вторая строка здесь немного сложная, поэтому давайте разберем ее по шагам. Свойство SpeechRecognitionEvent.results возвращает объект SpeechRecognitionResultList, содержащий объекты SpeechRecognitionResult. Он имеет getter, поэтому к нему можно обращаться как к массиву — поэтому первый [0] возвращает SpeechRecognitionResult на позиции 0. Каждый объект SpeechRecognitionResult содержит объекты SpeechRecognitionAlternative, которые содержат отдельные распознанные слова. Они также имеют getter, поэтому к ним можно обращаться как к массивам — второй [0] поэтому возвращает SpeechRecognitionAlternative на позиции 0. Затем мы возвращаем его свойство transcript для получения строки, содержащей распознанный результат в виде строки, устанавливаем цвет фона на этот цвет и сообщаем о распознанном цвете как диагностическое сообщение в пользовательском интерфейсе.
Мы также используем событие speechend, чтобы остановить работу службы распознавания речи (используя SpeechRecognition.stop()) после распознавания одного слова и окончания его произнесения:
recognition.onspeechend = () => {
recognition.stop();
};
Обработка ошибок и нераспознанной речи
Последние два обработчика предназначены для обработки случаев, когда распознанная речь не была в определенной грамматике или произошла ошибка. Событие nomatch должно обрабатывать первый упомянутый случай, хотя обратите внимание, что в данный момент оно, похоже, не срабатывает должным образом; оно просто возвращает то, что было распознано:
recognition.onnomatch = (event) => {
diagnostic.textContent = "I didn't recognize that color.";
};
Событие error обрабатывает случаи, когда возникает фактическая ошибка распознавания — свойство SpeechRecognitionErrorEvent.error содержит возвращенную фактическую ошибку:
recognition.onerror = (event) => {
diagnostic.textContent = `Error occurred in recognition: ${event.error}`;
};
Синтез речи
Синтез речи (также известный как текст в речь или TTS) включает в себя получение синтезированного текста, содержащегося в приложении, в речь и воспроизведение его через динамики устройства или аудиовыход.
Web Speech API имеет основной интерфейс контроллера для этого — SpeechSynthesis — плюс ряд тесно связанных интерфейсов для представления текста для синтеза (известного как высказывания), голосов, которые будут использоваться для высказывания, и т. д. Опять же, большинство операционных систем имеют какой-либо синтез речи, который будет использоваться API для этой задачи, если он доступен.
Демо
Для демонстрации простого использования синтеза речи веб-браузера, мы предоставили демонстрацию под названием Speak easy synthesis. Она включает набор элементов управления формой для ввода текста, который нужно синтезировать, и настройки тона, скорости и голоса, используемых при произношении текста. После ввода текста вы можете нажать Enter/Return, чтобы услышать его.
Чтобы запустить демонстрацию, перейдите по ссылке на демонстрацию в поддерживающем мобильном браузере.
HTML и CSS
HTML и CSS снова довольно тривиальны, содержат заголовок, некоторые инструкции по использованию и форму с некоторыми простыми элементами управления. Элемент <select> изначально пуст, но заполняется <option> с помощью JavaScript (см. ниже).
<h1>Speech synthesizer</h1>
<p>
Enter some text in the input below and press return to hear it. Change voices
using the dropdown menu.
</p>
<form>
<input type="text" class="txt" />
<div>
<label for="rate">Rate</label
><input type="range" min="0.5" max="2" value="1" step="0.1" id="rate" />
<div class="rate-value">1</div>
<div class="clearfix"></div>
</div>
<div>
<label for="pitch">Pitch</label
><input type="range" min="0" max="2" value="1" step="0.1" id="pitch" />
<div class="pitch-value">1</div>
<div class="clearfix"></div>
</div>
<select></select>
</form>
JavaScript
Давайте рассмотрим JavaScript, который питает это приложение.
Установка переменных
Прежде всего, мы получаем ссылки на все элементы DOM, участвующие в пользовательском интерфейсе, но более интересно, мы получаем ссылку на Window.speechSynthesis. Это точка входа API — она возвращает экземпляр SpeechSynthesis, интерфейс-контроллер для синтеза речи в браузере.
const synth = window.speechSynthesis;
const inputForm = document.querySelector("form");
const inputTxt = document.querySelector(".txt");
const voiceSelect = document.querySelector("select");
const pitch = document.querySelector("#pitch");
const pitchValue = document.querySelector(".pitch-value");
const rate = document.querySelector("#rate");
const rateValue = document.querySelector(".rate-value");
const voices = [];
Заполнение элемента select
Чтобы заполнить элемент <select> различными вариантами голосов, доступными на устройстве, мы написали функцию populateVoiceList(). Сначала мы вызываем SpeechSynthesis.getVoices(), которая возвращает список всех доступных голосов, представленных объектами SpeechSynthesisVoice. Затем мы перебираем этот список — для каждого голоса создаем элемент <option>, устанавливаем его текстовое содержимое, отображающее имя голоса (полученное из SpeechSynthesisVoice.name), язык голоса (полученный из SpeechSynthesisVoice.lang) и -- DEFAULT если голос является стандартным для синтезатора (проверяется путем проверки, возвращает ли SpeechSynthesisVoice.default значение true.)
Мы также создаем атрибуты data- для каждого варианта, содержащие имя и язык связанного голоса, чтобы мы могли легко получить их позже, а затем добавляем варианты как дочерние элементы select.
function populateVoiceList() {
voices = synth.getVoices();
for (const voice of voices) {
const option = document.createElement("option");
option.textContent = `${voice.name} (${voice.lang})`;
if (voice.default) {
option.textContent += " — DEFAULT";
}
option.setAttribute("data-lang", voice.lang);
option.setAttribute("data-name", voice.name);
voiceSelect.appendChild(option);
}
}
Старые браузеры не поддерживают событие voiceschanged, и просто возвращают список голосов при вызове SpeechSynthesis.getVoices(). В то время как в других, таких как Chrome, необходимо подождать, пока событие не сработает, прежде чем заполнять список. Чтобы учесть оба случая, мы выполняем функцию, как показано ниже:
populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList;
}
Произнесение введенного текста
Далее, мы создаем обработчик событий для начала произнесения текста, введенного в поле ввода. Мы используем обработчик onsubmit в форме, чтобы действие происходило при нажатии Enter/Return. Сначала мы создаем новый экземпляр SpeechSynthesisUtterance() с помощью его конструктора — в него передается значение ввода текста в качестве параметра.
Далее, нам нужно определить, какой голос использовать. Мы используем свойство HTMLSelectElement selectedOptions для возврата текущего выбранного элемента <option>. Затем мы используем атрибут data-name этого элемента, находим объект SpeechSynthesisVoice, имя которого соответствует значению этого атрибута. Мы устанавливаем соответствующий объект голоса в качестве значения свойства SpeechSynthesisUtterance.voice.
Наконец, мы устанавливаем SpeechSynthesisUtterance.pitch и SpeechSynthesisUtterance.rate на значения соответствующих элементов формы диапазона. Затем, выполнив все необходимые приготовления, мы запускаем произношение высказывания, вызвав SpeechSynthesis.speak(), передав ему экземпляр SpeechSynthesisUtterance в качестве параметра.
inputForm.onsubmit = (event) => {
event.preventDefault();
const utterThis = new SpeechSynthesisUtterance(inputTxt.value);
const selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for (const voice of voices) {
if (voice.name === selectedOption) {
utterThis.voice = voice;
}
}
utterThis.pitch = pitch.value;
utterThis.rate = rate.value;
synth.speak(utterThis);
В заключительной части обработчика мы включаем событие pause, чтобы продемонстрировать, как можно использовать SpeechSynthesisEvent с пользой. При вызове SpeechSynthesis.pause() возвращается сообщение с номером и именем символа, на котором было приостановлено произношение.
utterThis.onpause = (event) => {
const char = event.utterance.text.charAt(event.charIndex);
console.log(
`Speech paused at character ${event.charIndex} of "${event.utterance.text}", which is "${char}".`,
);
};
Наконец, мы вызываем blur() на поле ввода текста. Это в основном для скрытия клавиатуры в Firefox OS.
inputTxt.blur(); }
Обновление отображаемых значений тона и скорости
Последняя часть кода обновляет значения pitch/rate, отображаемые в пользовательском интерфейсе, каждый раз, когда перемещаются позиции ползунков.
pitch.onchange = () => {
pitchValue.textContent = pitch.value;
};
rate.onchange = () => {
rateValue.textContent = rate.value;
};
© 2005–2024 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API