When
2017/03/28
At
自己紹介
ちきさん
(Tomohiro Noguchi)
Twitter/GitHub/Qiita: @ovrmrw
ただのSIer。
Angular Japan User Group (ng-japan)スタッフ。
今回のGitHubリポジトリ
フロントエンド: ovrmrw/webaudio-meetup-react-example
バックエンド: ovrmrw/cognitive-server-starter
あるとき僕は、リアルタイム音声認識をやりたいと思い立った。
何から始めればいいんだろう?
リアルタイムに音声入力したいと思ったら把握しなければいけないこと。
- Navigator.getUserMedia
- AudioContext
- AudioContext.createMediaStreamSource()
- AudioContext.createScriptProcessor()
- ScriptProcessorNode.onaudioprocess
- WebSocket
- 。。。。。その他諸々
つらい
探したらお手軽っぽいの見つかった。
Watson Speech to Text
Speech-to-Text APIのデモサイト。
マイクがあれば音声認識を実際に試すことができる。
watson-developer-cloud/speech-to-text-nodejs
前ページのデモサイトをgit cloneして動かせるGitHubリポジトリ。
サンプルコードが以前はjQueryベースだったが、今はReactベースになって多少読みやすくなった。
Watsonデモサイトで使われているお手軽ライブラリ
-
saebekassebil/microphone-stream
- WebAudio APIをうまいことラップしてStreamとして扱えるようにするライブラリ。
-
watson-developer-cloud/speech-javascript-sdk
- 上記のライブラリをさらにラップしてWatson Speech-to-Text APIを簡単に扱えるようにするライブラリ。
WebAudio APIを直接叩かずにリアルタイム音声入力できる。しかもWatsonで音声認識できる。
(connpassより)
イベント概要
WebAudio.tokyoはWeb Audio APIのための勉強会です。
_人人人人人人人人人人人人人人人人人人人_
> Web Audio APIのための勉強会です。 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
Reactでミニマムなサンプルコードを書いてみよう
(デモ)
必要なライブラリをimport
import * as recognizeMicrophone from 'watson-speech/speech-to-text/recognize-microphone'
(TypeScriptの場合)
Watsonを使うためのTokenを取得するメソッド
getTokenAsync() {
return fetch('http://localhost:4000/api/watson/speech-to-text/token')
.then(res => res.json())
.then(data => data.token)
}
(Tokenを取得するためのバックエンドサーバーが localhost:4000 で稼働している)
AudioContextをオン/オフするためのメソッド
RECボタン/STOPボタンがクリックされたときに呼ばれる。
toggleMicrophoneState() {
if (this.recognizeStream) {
this.stopRecognizeStream()
} else if (!this.isRecording) {
this.isRecording = true
this.getTokenAsync()
.then(token => {
this.setState({ transcripts: [] })
this.startRecognizeStream(token)
})
}
}
RecognizeStreamを開始するメソッド
Watsonサーバーから返ってくる認識後のデータは stream.on('data', .....)
で受け取る。
startRecognizeStream(token) {
const stream = recognizeMicrophone({
token,
model: 'ja-JP_BroadbandModel',
objectMode: true,
extractResults: true,
})
stream.on('data', data => {
if (data.final) {
const transcript = data.alternatives[0].transcript
this.setState({ transcripts: [...this.state.transcripts, transcript] })
}
})
this.recognizeStream = stream
}
RecognizeStreamを終了するメソッド
stream
の stop()
, removeAllListeners()
を呼ぶのはお作法みたいなもの。
stopRecognizeStream() {
if (this.recognizeStream) {
this.recognizeStream.stop()
this.recognizeStream.removeAllListeners()
}
this.isRecording = false
this.recognizeStream = null
}
src/Mic.tsx の全コード
import * as React from 'react'
import * as recognizeMicrophone from 'watson-speech/speech-to-text/recognize-microphone'
export class Mic extends React.PureComponent {
private isRecording = false
private recognizeStream = null
constructor(props) {
super(props)
this.state = { transcripts: [] }
}
getTokenAsync() {
return fetch('http://localhost:4000/api/watson/speech-to-text/token')
.then(res => res.json() as any)
.then(data => data.token)
}
async toggleMicrophoneState() {
if (this.recognizeStream) {
this.stopRecognizeStream()
} else if (!this.isRecording) {
this.isRecording = true
await this.getTokenAsync()
.then(token => {
this.setState({ transcripts: [] })
this.startRecognizeStream(token)
})
}
}
startRecognizeStream(token) {
const stream = recognizeMicrophone({
token,
model: 'ja-JP_BroadbandModel',
objectMode: true,
extractResults: true,
})
stream.on('data', data => {
if (data.final) {
const transcript = data.alternatives[0].transcript
this.setState({ transcripts: [...this.state.transcripts, transcript] })
}
})
this.recognizeStream = stream
}
stopRecognizeStream() {
if (this.recognizeStream) {
this.recognizeStream.stop()
this.recognizeStream.removeAllListeners()
}
this.isRecording = false
this.recognizeStream = null
}
render() {
const buttonName = !this.recognizeStream ? 'REC' : 'STOP'
return (
<div>
<div>Mic Component</div>
<button onClick={() => this.toggleMicrophoneState().then(() => this.forceUpdate())}>
{buttonName}
</button>
<div>{this.state.transcripts.join(', ')}</div>
</div>
)
}
}