speech api
几天前,我在2014年WebTech大会上发表了题为“ 交谈和收听网页”的演讲,讨论了Web Speech API以及开发人员可以如何使用它来改善用户体验。 该演讲的灵感来自于我为SitePoint写的两篇名为《 介绍Web语音API和Talking Web页面以及语音合成API》的文章 。
在本教程中,我们将基于获得的知识,并开发一个使用此API定义的两个接口的演示。 如果您需要Web语音API的介绍,我建议您阅读前面提到的两篇文章,因为这将假定您对它有所了解。 玩得开心!
开发互动表格
本文的目的是构建一个交互式表单,我们的用户可以在其中填充自己的声音。 为了这个示例,我们将开发一个注册表单,但是您可以将相同的概念应用于所需的任何表单。 要记住的一个重要概念是, 语音的使用绝不应成为唯一的输入来源,因为无论语音识别器多么精确,它都不会是完美的。 因此,用户应始终能够修改任何字段以修复识别器所犯的任何错误。
在此演示中,我们将提供一个按钮,单击该按钮后,它将开始向用户提问,然后继续进行交互,用户说出答案。 识别器将语音转换为放置在文本字段中的文本。 互动完成后,这意味着我们表格的所有字段都已填写,我们的应用程序将很礼貌并感谢用户。
最后一点,请记住,在撰写本文时,Web Speech API尚处于试验阶段,仅受Chrome完全支持。 因此,我们的实验只能在此浏览器中进行。 事不宜迟,让我们开始构建注册表单的标记。
注册表HTML
为了使事情尽可能简单,我们的表单将只包含三个字段,但是您可以根据需要添加任意多个字段。 特别是,我们将要求用户填写姓名,姓氏和国籍。 如果您具有HTML的基本知识,则执行此任务应该非常容易。 我建议您在看下面的代码(我的实现)之前尝试实现它:
<form>
<label for="form-demo-name">Name:</label>
<input id="form-demo-name" />
<label for="form-demo-surname">Surname:</label>
<input id="form-demo-surname" />
<label for="form-demo-nationality">Nationality:</label>
<input id="form-demo-nationality" />
<input id="form-demo-voice" type="submit" value="Start" />
</form>
前面的代码只显示了经典形式,只能使用键盘或类似的输入设备来填充。 因此,我们需要找到一种方法来指定我们要对表单中定义的每个字段提出的问题。 一个好的简单解决方案是使用HTML5的data-*
属性。 特别是,我们将为每个label
- input
对指定一个data-question
属性。 我决定将属性设置为与input
关联的label
,但是您可以轻松更改演示以在input
元素上定义属性。
结果代码如下所示:
<form>
<label for="form-demo-name" data-question="What's your name?">Name:</label>
<input id="form-demo-name" />
<label for="form-demo-surname" data-question="What's your surname?">Surname:</label>
<input id="form-demo-surname" />
<label for="form-demo-nationality" data-question="What's your nationality?">Nationality:</label>
<input id="form-demo-nationality" />
<input id="form-demo-voice" type="submit" value="Start" />
</form>
无论您是否感到惊讶,这都是我们创建交互式表单所需的全部标记。 现在,我们通过讨论JavaScript代码来深入研究演示的核心。
添加业务逻辑
要开发我们形式的业务逻辑,我们需要三个要素:语音合成器,语音识别器和promise 。 我们需要语音合成器来发出声音,以询问用户使用data-question
属性定义data-question
。 语音识别器用于将用户的响应转换为将设置为每个字段的值的文本。 最后,我们需要承诺避免回调地狱!
。
WebSpeech API由异步操作驱动,因此我们需要一种同步所有操作的方法。 在问完问题后 ,我们需要开始识别用户的语音,并且在用户说出答案并且识别器完成其工作之后 ,我们必须提出一个新问题。 因此,我们需要同步连续(串行)异步操作的变量集。 我们可以通过在代码中采用promise来轻松解决此问题。 如果您需要有关什么是承诺的入门知识,SitePoint会为您提供“ JavaScript承诺概述 ”一文。 杰克·阿奇博尔德(Jake Archibald)撰写了另一篇非常好的文章,标题为《 JavaScript Promises:There and back back》 。
我们的代码将在逻辑上分为两部分:一个支持Web Speech API并充当Promise的产生者的支持库,以及将使用Promise的代码。 在本文的下两节中,我们将讨论它们。
开发支持库
如果您对Web Speech API的工作方式有一定的了解,那么理解支持库就不会很困难。
我们将定义一个对象常量,并将其分配给一个名为Speech
的变量。 该对象有两种方法: speak
和recognize
。 前者接受语音文本,并负责发出音频,并创建与此操作相关的承诺。 如果没有错误发生( error
事件),则将兑现承诺;如果触发了error
事件, error
被拒绝。 如果浏览器不支持该API,那么诺言也将被拒绝。 recognize
方法用于识别用户的语音。 它不接受任何参数,并返回通过将其传递给所创建的Promise的resolve方法识别的文本。 正如您将看到的,与speak
相比, recognize
有点复杂,因为它必须处理更多的情况。 当最终结果可用或出现任何错误时,被recognize
创建的承诺将被解决或被拒绝。 请注意,该代码还将处理几天前在Windows 8.1(#428873)上发现的问题 。
我们的支持库的完整代码如下所示:
var Speech = {
speak: function(text) {
return new Promise(function(resolve, reject) {
if (!SpeechSynthesisUtterance) {
reject('API not supported');
}
var utterance = new SpeechSynthesisUtterance(text);
utterance.addEventListener('end', function() {
console.log('Synthesizing completed');
resolve();
});
utterance.addEventListener('error', function (event) {
console.log('Synthesizing error');
reject('An error has occurred while speaking: ' + event.error);
});
console.log('Synthesizing the text: ' + text);
speechSynthesis.speak(utterance);
});
},
recognize: function() {
return new Promise(function(resolve, reject) {
var SpeechRecognition = SpeechRecognition ||
webkitSpeechRecognition ||
null;
if (SpeechRecognition === null) {
reject('API not supported');
}
var recognizer = new SpeechRecognition();
recognizer.addEventListener('result', function (event) {
console.log('Recognition completed');
for (var i = event.resultIndex; i < event.results.length; i++) {
if (event.results[i].isFinal) {
resolve(event.results[i][0].transcript);
}
}
});
recognizer.addEventListener('error', function (event) {
console.log('Recognition error');
reject('An error has occurred while recognizing: ' + event.error);
});
recognizer.addEventListener('nomatch', function (event) {
console.log('Recognition ended because of nomatch');
reject('Error: sorry but I could not find a match');
});
recognizer.addEventListener('end', function (event) {
console.log('Recognition ended');
// If the Promise isn't resolved or rejected at this point
// the demo is running on Chrome and Windows 8.1 (issue #428873).
reject('Error: sorry but I could not recognize your speech');
});
console.log('Recognition started');
recognizer.start();
});
}
};
将所有零件放在一起
有了我们的支持库之后,我们需要编写代码来检索我们指定的问题,并与支持库进行交互以创建交互式表单。
我们要做的第一件事是检索表单的所有label
s,因为我们将使用它们的for
属性来检索input
s和data-question
属性来提出问题。 此操作由以下语句执行:
var fieldLabels = [].slice.call(document.querySelectorAll('label'));
回顾我们如何编写标记,我们可以通过保持label
- input
对(即问题答案对)耦合来缩短所需的代码。 我们可以使用支持函数来实现这一点,我们将其称为formData
。 其目标是返回每个label
( input
对)产生的新承诺。 将表单中的每个label
和input
都视为唯一的组件,而不是不同的实体,这使我们减少了所需的代码,因为我们可以提取出更抽象的代码并在它们上循环。
formData
函数的代码及其调用方式如下所示:
function formData(i) {
return promise.then(function() {
return Speech.speak(fieldLabels[i].dataset.question);
})
.then(function() {
return Speech.recognize().then(function(text) {
document.getElementById(fieldLabels[i].getAttribute('for')).value = text;
});
});
}
for(var i = 0; i < fieldLabels.length; i++) {
promise = formData(i);
}
免费学习PHP!
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
因为我们已经按照formData
函数中所示的那样对诺言进行了耦合,所以我们需要一个初始诺言,将其解析为允许其他诺言启动。 通过创建一个在上一个代码片段循环之前立即解决的promise,可以完成此任务:
var promise = new Promise(function(resolve) {
resolve();
});
最后,我们要感谢您的用户,但也要抓住我们的过程中可能产生的任何错误:
promise.then(function() {
return Speech.speak('Thank you for filling the form!');
})
.catch(function(error) {
alert(error);
});
至此,我们的代码几乎完成了。 最后一步是将本节的所有代码放在用户单击按钮时执行的函数中。
结果
正如您所指出的,我没有讨论此演示的样式,因为它完全不相关,您可以自由编写自己的样式。 作为补充说明,我还想提及一下,在下面的演示中,我还创建了一个简单的微调器,当识别器准备就绪时可以提供视觉反馈。
开发的代码结果如下所示,但也可以作为JSBin使用 :
结论
在本教程中,我们开发了一种简单但功能齐全的交互式表单,用户可以使用语音填写该表单。 为此,我们使用了一些最先进的技术,例如Web Speech API和Promise。 该演示应该使您了解使用新JavaScript API可以做什么以及它们如何改善用户体验。 最后,请记住,您只能在Chrome中使用此演示。
我希望您喜欢本教程并学到了一些有趣的新东西。
翻译自: https://www.sitepoint.com/experimenting-web-speech-api/
speech api