Skip to content

Instantly share code, notes, and snippets.

@kounoike
Created February 16, 2022 09:17
Show Gist options
  • Save kounoike/4b91e6b51254e5d675d5136c139142b7 to your computer and use it in GitHub Desktop.
Save kounoike/4b91e6b51254e5d675d5136c139142b7 to your computer and use it in GitHub Desktop.
vosk-browserのお試し
<html>
<head>
<title>vosk test</title>
<script type="application/javascript" src="https://cdn.jsdelivr.net/npm/vosk-browser@0.0.3/dist/vosk.js"></script>
<script>
//
let model = null
// 初期化処理
async function init() {
// 権限取得のための素振り
const s = await navigator.mediaDevices.getUserMedia({video: false, audio: true})
s.getTracks().forEach(t => t.stop())
// マイク列挙処理
const select = document.getElementById('micSelect')
navigator.mediaDevices.enumerateDevices().then(devices => {
devices.filter(d => d.kind === "audioinput").forEach(d => {
const option = document.createElement('option')
option.value = d.deviceId
option.innerText = d.label
select.append(option)
})
})
// 同一ディレクトリの model.tar.gz を(Webから)読み込む。
model = await Vosk.createModel('model.tar.gz')
// ボタン有効化
document.getElementById('start').disabled = false
}
// ボタンの処理
async function start() {
document.getElementById('start').disabled = true
const recognizer = new model.KaldiRecognizer()
const result = document.getElementById('result')
// 文章確定時はdivに流し込む
recognizer.on('result', event => {
const p = document.createElement('p')
p.innerText = event.result.text
result.append(p)
})
// 部分的結果はspanでリアルタイム表示してみる
recognizer.on('partialresult', event => {
const p = document.getElementById('partialResult')
p.innerText = event.result.partial
})
// 選択されたマイクをオープン
const select = document.getElementById('micSelect')
const stream = await navigator.mediaDevices.getUserMedia({
video: false,
audio: {
deviceId: select.value,
echoCancellation: true,
noiseSuppression: true,
channelCount: 1
}
})
// WebAudioでノードをつなぐ
const audioContext = new AudioContext()
// AudioWorkletにするのも複雑なんでdeprecatedだけどサンプル通りScriptProcessorNodeで実装
// 言語バインディングによって異なるが、JavaScriptバインディングは AudioBuffer を受け取るので
// ScriptProcessorNode が一番簡単。f32-plannerでも受け取ってくれる
const recognizerNode = audioContext.createScriptProcessor(4096, 1, 1)
recognizerNode.onaudioprocess = event => {
try {
// 認識エンジンに突っ込む
recognizer.acceptWaveform(event.inputBuffer)
// outputをゼロフィル(無音化)しておく
// 何もしなくても無音かも
event.outputBuffer.getChannelData(0).fill(0)
} catch (err) {
console.error(err)
}
}
// destinationまでつながないと動かないような・・・?
const sourceNode = audioContext.createMediaStreamSource(stream)
sourceNode.connect(recognizerNode).connect(audioContext.destination)
}
</script>
</head>
<body onload="init()">
<select id="micSelect">
</select>
<button id="start" onclick="start()" disabled="true">start</button>
<div><span>PartialResult:</span><span id="partialResult"></span></div>
<div id="result"></div>
</body>
</html>

動かし方

モデルの準備

https://alphacephei.com/vosk/models からモデルを落として、modelディレクトリにリネーム、tar.gzにする

wget https://alphacephei.com/vosk/models/vosk-model-small-ja-0.22.zip
unzip vosk-model-small-ja-0.22.zip
mv vosk-model-small-ja-0.22 model
tar zcf model.tar.gz model

もちろん日本語以外のモデルでも同様にmodelディレクトリにリネームしてtar.gzにすればOK

htmlの配信

test.html と上記の model.tar.gz を置いたディレクトリで python -m http.server 8000 などして http 配信する

実行

http://localhost:8000 を開いてマイク入力を許可、マイクデバイスを選択してStart ボタンを押す。マイクに対して入力した音声が認識されて画面に表示されていく。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment