react-speech-recognition
这是一个React钩子,可以将来自麦克风的语音转换为文本,并使其在React组件中可用。
工作原理
useSpeechRecognition
是一个React钩子,它使组件能够访问从用户麦克风捕获的语音转录。
SpeechRecognition
管理Web Speech API的全局状态,提供开启和关闭麦克风的功能。
底层使用Web Speech API。请注意,目前浏览器对此API的支持有限,Chrome提供最佳体验 - 更多信息请参见支持的浏览器。
此版本需要React 16.8以上版本以支持React钩子。如果你习惯使用react-speech-recognition
的2.x版本或想使用旧版React,可以在这里查看旧版README。如果你想迁移到3.x版本,请参见这里的迁移指南。
有用链接
安装
安装命令:
npm install --save react-speech-recognition
在React代码中导入:
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition'
基本示例
使用此钩子的最基本组件示例如下:
import React from 'react';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const Dictaphone = () => {
const {
transcript,
listening,
resetTranscript,
browserSupportsSpeechRecognition
} = useSpeechRecognition();
if (!browserSupportsSpeechRecognition) {
return <span>浏览器不支持语音识别。</span>;
}
return (
<div>
<p>麦克风:{listening ? '开启' : '关闭'}</p>
<button onClick={SpeechRecognition.startListening}>开始</button>
<button onClick={SpeechRecognition.stopListening}>停止</button>
<button onClick={resetTranscript}>重置</button>
<p>{transcript}</p>
</div>
);
};
export default Dictaphone;
你可以在本仓库附带的示例React应用中查看更多示例。请参见开发。
为什么应该使用polyfill
默认情况下,并非所有浏览器都支持语音识别,桌面版Chrome提供最佳的原生体验。为避免原生浏览器语音识别的局限性,建议将react-speech-recognition
与语音识别polyfill结合使用。原因如下:
- ✅ 使用polyfill,你的Web应用将在所有现代浏览器上支持语音功能(除Internet Explorer外)
- ❌ 不使用polyfill,你的Web应用仅在这里列出的浏览器上支持语音功能
- ✅ 使用polyfill,你的Web应用在各浏览器上将有一致的语音体验
- ❌ 不使用polyfill,不同的原生实现将产生不同的转录结果,准确度不同,格式也不同
- ✅ 使用polyfill,你可以控制谁在处理用户的语音数据
- ❌ 不使用polyfill,用户的语音数据将被发送到谷歌或苹果等大型科技公司进行转录
- ✅ 使用polyfill,
react-speech-recognition
将适用于商业应用 - ❌ 不使用polyfill,
react-speech-recognition
仍适用于个人项目或不需要跨浏览器支持的场景
react-speech-recognition
目前支持以下云服务提供商的polyfill:
跨浏览器示例
您可以在此处找到设置polyfill的完整指南。或者,这里有一个使用Speechly的快速(且免费)示例:
- 在您的Web应用中安装
@speechly/speech-recognition-polyfill
- 您需要一个Speechly应用ID。要获取一个,请在Speechly免费注册并按照此处的指南操作
- 以下是一个按下说话按钮的组件。上面的基本示例也可以正常使用。
import React from 'react';
import { createSpeechlySpeechRecognition } from '@speechly/speech-recognition-polyfill';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const appId = '<在此插入SPEECHLY应用ID>';
const SpeechlySpeechRecognition = createSpeechlySpeechRecognition(appId);
SpeechRecognition.applyPolyfill(SpeechlySpeechRecognition);
const Dictaphone = () => {
const {
transcript,
listening,
browserSupportsSpeechRecognition
} = useSpeechRecognition();
const startListening = () => SpeechRecognition.startListening({ continuous: true });
if (!browserSupportsSpeechRecognition) {
return <span>浏览器不支持语音识别。</span>;
}
return (
<div>
<p>麦克风:{listening ? '开启' : '关闭'}</p>
<button
onTouchStart={startListening}
onMouseDown={startListening}
onTouchEnd={SpeechRecognition.stopListening}
onMouseUp={SpeechRecognition.stopListening}
>按住说话</button>
<p>{transcript}</p>
</div>
);
};
export default Dictaphone;
检测浏览器对Web Speech API的支持
如果您选择不使用polyfill,本库在不支持语音识别的浏览器上仍能优雅地失败。建议您在用户的浏览器不支持时渲染一些备用内容:
if (!browserSupportsSpeechRecognition) {
// 渲染一些备用内容
}
支持的浏览器
没有polyfill的情况下,Web Speech API主要只由Google浏览器支持。截至2021年5月,以下浏览器支持Web Speech API:
- Chrome(桌面版):这是目前体验最流畅的选择
- Safari 14.1
- Microsoft Edge
- Chrome(Android版):关于这个平台需要注意的是,打开麦克风时可能会有令人烦恼的哔哔声。这是Android操作系统的一部分,无法从浏览器控制
- Android webview
- Samsung Internet
对于所有其他浏览器,您可以使用上面描述的SpeechRecognition.browserSupportsSpeechRecognition
函数渲染备用内容。或者,如前所述,您可以集成一个polyfill。
检测用户拒绝访问麦克风
即使浏览器支持Web Speech API,用户在开始转录之前仍需要授权使用麦克风。当react-speech-recognition
首次尝试开始监听时,会询问用户是否授权。此时,您可以通过isMicrophoneAvailable
状态检测用户是否拒绝访问。当这个值变为false
时,建议您禁用语音驱动的功能,并提示需要麦克风访问权限才能使用这些功能。
if (!isMicrophoneAvailable) {
// 渲染一些备用内容
}
控制麦克风
在使用转录内容之前,您应该熟悉SpeechRecognition
,它可以让您控制麦克风。麦克风的状态是全局的,所以您在这个对象上调用的任何函数都会影响使用useSpeechRecognition
的所有组件。
打开麦克风
要开始监听语音,调用startListening
函数。
SpeechRecognition.startListening()
这是一个异步函数,所以如果您想在麦克风打开后执行某些操作,需要等待它完成。
关闭麦克风
要关闭麦克风,但仍继续处理正在进行的语音,调用stopListening
。
SpeechRecognition.stopListening()
要关闭麦克风并取消正在进行的语音处理,调用abortListening
。
SpeechRecognition.abortListening()
使用麦克风转录内容
要在您的组件中使用麦克风转录内容,只需添加:
const { transcript } = useSpeechRecognition()
重置麦克风转录内容
要将转录内容设置为空字符串,您可以调用useSpeechRecognition
提供的resetTranscript
函数。请注意,这只在您的组件内部生效,不会影响使用语音识别的其他组件。
const { resetTranscript } = useSpeechRecognition()
命令
要在用户说出特定短语时做出响应,您可以向 useSpeechRecognition
钩子传入一个命令列表。每个命令都是一个具有以下属性的对象:
command
:这是一个字符串或RegExp
,表示您要监听的短语。如果您想为多个命令使用相同的回调函数,也可以在这里传入一个数组,每个值可以是字符串或RegExp
。callback
:当命令被说出时执行的函数。这个函数接收的最后一个参数始终是一个包含以下属性的对象:command
:匹配到的命令短语。当您为同一个回调函数提供多个命令短语时,这个属性可以用来确定是哪个短语触发了回调。resetTranscript
:一个将转录内容设置为空字符串的函数。
matchInterim
:决定是否将"中间"结果与命令进行匹配的布尔值。这会使您的组件更快地响应命令,但也会增加误报的可能性——即可能在未说出命令时检测到命令。默认为false
,只应为简单命令设置。isFuzzyMatch
:决定语音与command
的比较是基于相似度而非精确匹配的布尔值。模糊匹配对于容易发音错误或被语音识别引擎误解的命令(如地名、运动队名、餐厅菜单项)很有用。它适用于不含特殊字符的字符串字面量命令。如果command
是带有特殊字符的字符串或RegExp
,在进行模糊匹配时会被转换为不含特殊字符的字符串。匹配命令所需的相似度可以通过fuzzyMatchingThreshold
配置。isFuzzyMatch
默认为false
。当设置为true
时,会向callback
传递四个参数:command
的值(去除任何特殊字符)- 匹配
command
的语音 command
和语音之间的相似度- 上面
callback
描述中提到的对象
fuzzyMatchingThreshold
:当isFuzzyMatch
开启时,如果语音与command
的相似度高于这个值,就会调用callback
。只有在isFuzzyMatch
为true
时才应设置此值。取值范围在0
(匹配任何内容)到1
(需要完全匹配)之间。默认值为0.8
。bestMatchOnly
:当isFuzzyMatch
为true
时,此布尔值决定回调是否只应由最佳匹配的命令短语触发,而不是由所有匹配的模糊命令短语触发。这对于分配给同一回调函数的多个命令短语的模糊命令很有用——您可能只希望每个口头命令只触发一次回调。只有在isFuzzyMatch
为true
时才应设置此值。默认值为false
。
命令符号
为了使命令更容易编写,支持以下符号:
- 通配符:就是一个
*
,可以匹配多个单词:- 示例:
'I would like to order *'
- 匹配通配符的单词将作为参数传递给回调函数,每个通配符对应一个参数
- 示例:
- 命名变量:写作
:<name>
,可以匹配单个单词:- 示例:
'I am :height metres tall'
- 匹配命名变量的单词将作为参数传递给回调函数
- 示例:
- 可选词:用括号
(
和)
包围的短语,不需要匹配命令:- 示例:
'Pass the salt (please)'
- 上面的示例可以匹配
'Pass the salt'
和'Pass the salt please'
- 示例:
带命令的示例
import React, { useState } from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition'
const Dictaphone = () => {
const [message, setMessage] = useState('')
const commands = [
{
command: 'I would like to order *',
callback: (food) => setMessage(`Your order is for: ${food}`)
},
{
command: 'The weather is :condition today',
callback: (condition) => setMessage(`Today, the weather is ${condition}`)
},
{
command: 'My top sports are * and *',
callback: (sport1, sport2) => setMessage(`#1: ${sport1}, #2: ${sport2}`)
},
{
command: 'Pass the salt (please)',
callback: () => setMessage('My pleasure')
},
{
command: ['Hello', 'Hi'],
callback: ({ command }) => setMessage(`Hi there! You said: "${command}"`),
matchInterim: true
},
{
command: 'Beijing',
callback: (command, spokenPhrase, similarityRatio) => setMessage(`${command} and ${spokenPhrase} are ${similarityRatio * 100}% similar`),
// 如果 spokenPhrase 是 "Benji",消息将是 "Beijing and Benji are 40% similar"
isFuzzyMatch: true,
fuzzyMatchingThreshold: 0.2
},
{
command: ['eat', 'sleep', 'leave'],
callback: (command) => setMessage(`Best matching command: ${command}`),
isFuzzyMatch: true,
fuzzyMatchingThreshold: 0.2,
bestMatchOnly: true
},
{
command: 'clear',
callback: ({ resetTranscript }) => resetTranscript()
}
]
const { transcript, browserSupportsSpeechRecognition } = useSpeechRecognition({ commands })
if (!browserSupportsSpeechRecognition) {
return null
}
return (
<div>
<p>{message}</p>
<p>{transcript}</p>
</div>
)
}
export default Dictaphone
持续监听
默认情况下,当用户停止说话时,麦克风将停止监听。这反映了现代设备上"按下说话"按钮的方法。
如果您想持续监听,在调用 startListening
时将 continuous
属性设置为 true
。即使用户停止说话,麦克风也会继续监听。
SpeechRecognition.startListening({ continuous: true })
请注意,并非所有浏览器都很好地支持持续监听。特别是 Android 上的 Chrome 会不断重启麦克风,导致令人沮丧和嘈杂(因为蜂鸣声)的体验。为了避免在这些浏览器上启用持续监听,您可以使用 useSpeechRecognition
提供的 browserSupportsContinuousListening
状态来检测对此功能的支持。
if (browserSupportsContinuousListening) {
SpeechRecognition.startListening({ continuous: true })
} else {
// 备用行为
}
或者,您可以尝试使用填充库来在这些浏览器上启用持续监听。
更改语言
要监听特定语言,您可以在调用startListening
时传递一个语言标签(例如,'zh-CN'
表示中文)。有关支持的语言列表,请参阅此处。
SpeechRecognition.startListening({ language: 'zh-CN' })
故障排除
regeneratorRuntime is not defined
如果在使用此库时看到错误regeneratorRuntime is not defined
,您需要确保您的Web应用安装了regenerator-runtime
:
npm i --save regenerator-runtime
- 如果您使用NextJS,请在
_app.js
文件顶部添加:import 'regenerator-runtime/runtime'
。对于任何其他框架,请将其放在index.js
文件顶部
如何离线使用react-speech-recognition
?
不幸的是,Chrome在离线状态下无法进行语音识别。根据Web Speech API文档:在Chrome上,在网页上使用语音识别涉及基于服务器的识别引擎。您的音频会被发送到网络服务进行识别处理,因此它无法离线工作。
如果您正在构建离线Web应用,可以通过检查navigator.onLine
的值来检测浏览器是否离线。如果它是true
,您可以渲染由React Speech Recognition生成的转录文本。如果它是false
,建议渲染离线备用内容,表示语音识别已禁用。在线/离线API使用简单 - 您可以在这里阅读如何使用它。
开发
您可以运行一个使用react-speech-recognition
的示例React应用:
npm i
npm run dev
在http://localhost:3000
上,您可以对着麦克风说话,并在网页上看到您的语音转为文本。还有用于开启和关闭语音识别的控件。您可以在example
目录中对Web应用本身进行更改。您对Web应用或react-speech-recognition
本身所做的任何更改都将在浏览器中实时重新加载。
API文档
在此处查看API文档,或按照上面的指南学习如何使用react-speech-recognition
。
许可证
MIT