1. 概要
Google Chromeの Web Speech API を利用して音声認識し、結果を Discordのテキストチャンネルに書き込みをする方法を紹介します。
やっていることは、NAMAROIDの音声認識をChromeでやってみた とほぼ同様ですが、本記事では実装面を解説します。
本実装は Webサーバを介した、クライアント・サーバ形式で、相互のメッセージングに socket.ioを利用しています。
socket.ioを利用することにより、Web APIに比べて実装が簡単で、送受信の高速化が期待できます。
参考記事
- Discord Bot の登録方法
Discord Botアカウント初期設定ガイド for Developer
動作環境
- OS: Windows 10
- node: v9.11.1
- chrome: 78.X
ソースコード
2. 使い方
2.1 ライブラリのインストール
初回のみ npm install
(setting.bat) を実行して
2.2 Discord Bot・テキストチャンネルの設定
config/discord.json
で下記の2つを指定する
- Botのトークン
- 書き込み先のテキストチャンネル
2.3 サーバサイドの実行
-
node server.js
実行(start.bat) を実行 - ブラウザで http://localhost:4000 を開く
2.4 ブラウザ操作
- 『音声認識開始』ボタンをクリックして、音声認識かいし
- 『停止』ボタンで音声認識を終了
補足
音声入力がうまく出来ていないときは、マイクの使用許可設定が適切か確認してください。
3. 実装の解説
3.A クライアントサイド(index.html)
Chrome で音声認識して、サーバにテキストを送る
'server.js' を起動すると、http://localhost:4000
で 'index.html' にアクセスすることができます。
この index.html
がクライアントサイドになります。
音声認識のメイン処理は speech_recognition.js
で行われます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>音声認識 Discordブリッジ</title>
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap.min.css" >
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap-grid.min.css" >
<link rel="stylesheet" href="assets/bootstrap/css/bootstrap-reboot.min.css" >
<script src="assets/lib_js/jquery-3.3.1.min.js" ></script>
<script src="assets/bootstrap/js/bootstrap.js" ></script>
<script src="/socket.io/socket.io.js"></script> <!-- socket.io を読み込み -->
<script src="assets/js/speech_recognition.js"></script> <!-- メインロジック -->
<style>
.row { margin-top: 20px;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-sm-12">
<h3>Chromeで音声認識して、Discordに書き込み</h3>
</div>
</div>
<div class="row">
<div class="col-sm-5">
<button class="btn btn-primary" id="start_btn">音声認識開始</button> <!-- 音声認識開始ボタン -->
<button class="btn btn-secondary" id="end_btn">停止</button> <!-- 音声認識停止ボタン -->
</div>
<div class="col-sm-7 d-flex align-items-center">
<strong><span id="status" style="font-size: 24px"></span></strong> <!-- 音声認識 ON/OFF 表示 -->
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="card-text">
<span id="prosess"></span> <!-- 音声認識イベント表示 -->
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="card">
<div class="card-body">
<div class="card-text" id="content"></div> <!-- 認識したテキスト表示 -->
</div>
</div>
</div>
</div>
</div>
</body>
</html>
const socket = io.connect(); // ソケットio
const speech = new webkitSpeechRecognition(); // 音声認識APIの使用
speech.lang = "ja"; // 言語を日本語に設定
let keep_standby = false;
function update_prosess(text) { $("#prosess").text(text); } // 音声認識 スタンバイ/停止 表示
function update_status(text) { $("#status").html(text); } // 音声認識 イベント 表示
// 音声認識した文字表示
function update_result_text(text) {
update_prosess('[結果表示]');
$("#content").text(text);
console.log(text);
}
// 音声認識の結果取得時の処理
speech.onresult = result => {
const text = result.results[0][0].transcript;
update_result_text(text);
socket.emit('get_word', {word: text}); // 認識文字を socket.io 経由でサーバに送信する
};
// 音声認識の継続継続処理
speech.onend = () => {
if (keep_standby) speech.start();
else speech.stop();
};
speech.onspeechstart = () => update_prosess('[音声取得開始]');
speech.onspeechend = () => update_prosess('[解析開始]');
$(function () {
$("#start_btn").on('click', () => {
update_status('<span class="text-success">『音声認識スタンバイ』</span>');
keep_standby = true;
speech.start();
});
$("#end_btn").on('click', () => {
update_status('<span class="text-danger">『停止中』</span>');
update_prosess('[音声認識停止中]');
keep_standby = false;
speech.stop();
});
$("#end_btn").trigger('click'); // 初期
$("#start_btn").trigger('click'); // 自動スタート
});
音声認識の処理フロー
1. index.html: socket.io
, speech_recognition.js
を読み込み
/socket.io/socket.io.js
の実態ファイルがソースコード一式にないため、不思議な感じですが、このファイルは server.js
で socket.io
の設定をすると勝手に用意してくれます。
<script src="/socket.io/socket.io.js"></script> <!-- socket.io を読み込み -->
<script src="assets/js/speech_recognition.js"></script> <!-- メインロジック -->
2. speech_recognition.js: socket.io オブジェクト取得
サーバ側(server.js)へのテキスト送信はこのオブジェクトを介して行います。
const socket = io.connect(); // ソケットio
3. speech_recognition.js: "音声認識APIの使用"
音声認識のオブジェクト(speech)を取得します。
音声認識に関わる処理はこちらを介して行います。
その際、speech.lang = "ja"
をお忘れなく。
const speech = new webkitSpeechRecognition(); // 音声認識APIの使用
speech.lang = "ja";
4. speech_recognition.js: $("#start_btn").on
index.html で表示している、『音声認識開始』ボタンをクリックした時のイベント。
ここの speech.start();
で音声認識が開始されます。
以降、音声認識処理が完了すると speech.onresult
で、音声認識した文字列を取得出来ます。
$("#start_btn").on('click', () => {
update_status('<span class="text-success">『音声認識スタンバイ』</span>');
keep_standby = true;
speech.start();
});
5. speech_recognition.js: speech.onresult
でサーバ(server.js)への文字送信
音声認識した文字列は result.results[0][0].transcript;
に格納されています。大抵このまま決め打ちでいいようです。
細かい仕様は https://wicg.github.io/speech-api/#speechreco-result を参照してください。
6. speech_recognition.js: speech.onend
で音声認識を継続
処理を継続するための処理です。
5で keep_standby = true
として、このフラグがtrue
であれば、speech.start()
をコールして継続処理をします。
B. サーバーサイド(server.js)
音声認識文字を受け取り、Discord の テキストチャンネル書き込む
server.js
では クライアント側のspeech_recognition.js
の socket.emit
で送信される文字を取得して、Discord のテキストチャンネルに書き込みをします。
const PORT = 4000;
const express = require('express');
const os = require('os');
const app = express();
app.use(express.static(__dirname));
const server = require('http').createServer(app).listen(PORT);
const io = require('socket.io').listen(server);
// ログイン処理
const config = require("./config/discord");
const Discord = require('discord.js');
const client = new Discord.Client();
const token = config.token;
client.on('ready', () => {
console.log('start server');
console.log(`open chrome: http://localhost:${PORT}`);
const targetTextChannel = client.channels.find(val => val.id === config.channel_id); // 指定テキストチャンネルを取得
io.sockets.on('connection', function(socket) {
socket.on('get_word', function (data) {
if(data === undefined || data === "" || data === null) return;
console.log(data);
targetTextChannel.send(data.word);
});
});
});
client.login(token);
音声認識の文字取得・テキストチャンネル書き込み処理フロー
1. Webサーバー
expressを利用して index.html 用の Webサーバを立ち上げ、Webサーバに socket.ioを追加する。
const app = express();
app.use(express.static(__dirname));
const server = require('http').createServer(app).listen(PORT);
const io = require('socket.io').listen(server);
2. Discord Botの設定
discord.js
を利用して Botを起動させる。
その際、config/discord.json
にDiscord Bot トークンと、書き込みをするDiscordテキストチャンネルIDを記載する。
{
"token": "Discord bot token",
"channel_id": "テキストチェンネルID"
}
client.login(token)
で Botが起動して、起動完了後client.on('ready', () => {})
がコールされます。
const config = require("./config/discord");
const Discord = require('discord.js');
const client = new Discord.Client();
const token = config.token;
...
client.login(token);
3. 指定のテキストチャンネルを取得
config.channel_id
に一致する channelを取得します。
find(val => val.name === 'チャンネル名')
とすると、チャンネル名でチャンネルを取得できます。
const targetTextChannel = client.channels.find(val => val.id === config.channel_id); // 指定テキストチャンネルを取得
4. socket.io の接続待ち
index.html側で socket.ioに接続するのを待ち、接続があった場合はio.sockets.on('connection', () => {})
が実行されます。
この処理は index.htmlを開いたページ毎にコールされ、音声入力する index.htmlは複数でも対応可能です。
5. 取得文字をテキストチャンネルにポスト
index.html側で get_word
イベントを発火すると、下記のget_word
がコールされます。
data.word
に音声認識した文字列が格納されているので、それを送信するだけで、テキストチャンネルに書き込みをします。
socket.on('get_word', function (data) {
if(data === undefined || data === "" || data === null) return;
console.log(data);
targetTextChannel.send(data.word);
});
最後に
google chromeの音声認識は無料で、API利用手続きなどをする必要もないので、個人利用するのであればすごく便利ですね。
google Cloud の STT(Speech-to-Text)も低料金で利用できるのですが、音声処理周りの実装やAPI利用のための設定が大変ですので、Chromeの Web Speechが一番楽です。
音声入力は未来感があって、筆者はとてもワクワクするインターフェイスだと思っています!