5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Chromeで音声認識して、Discordに書き込み

Last updated at Posted at 2019-12-12

1. 概要

Google Chromeの Web Speech API を利用して音声認識し、結果を Discordのテキストチャンネルに書き込みをする方法を紹介します。
やっていることは、NAMAROIDの音声認識をChromeでやってみた とほぼ同様ですが、本記事では実装面を解説します。

本実装は Webサーバを介した、クライアント・サーバ形式で、相互のメッセージングに socket.ioを利用しています。
socket.ioを利用することにより、Web APIに比べて実装が簡単で、送受信の高速化が期待できます。

スクリーンショット 2019-12-12 17.22.21.png アイコンは[おむ烈 様](https://seiga.nicovideo.jp/seiga/im4842809)のフリーアイコンをお借りしております!

参考記事

動作環境

  • 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 サーバサイドの実行

  1. node server.js 実行(start.bat) を実行
  2. ブラウザで http://localhost:4000 を開く

2.4 ブラウザ操作

  1. 『音声認識開始』ボタンをクリックして、音声認識かいし
  2. 『停止』ボタンで音声認識を終了

スクリーンショット 2019-12-12 17.13.00.png

補足
音声入力がうまく出来ていないときは、マイクの使用許可設定が適切か確認してください。

3. 実装の解説

3.A クライアントサイド(index.html)

Chrome で音声認識して、サーバにテキストを送る

'server.js' を起動すると、http://localhost:4000 で 'index.html' にアクセスすることができます。
この index.htmlがクライアントサイドになります。

音声認識のメイン処理は speech_recognition.js で行われます。

index.html
<!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>
speech_recognition.js
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.jssocket.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.jssocket.emit で送信される文字を取得して、Discord のテキストチャンネルに書き込みをします。

server.js
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を追加する。

server.js
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', () => {})がコールされます。

server.js
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 === 'チャンネル名')とすると、チャンネル名でチャンネルを取得できます。

server.js
    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に音声認識した文字列が格納されているので、それを送信するだけで、テキストチャンネルに書き込みをします。

server.js
 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が一番楽です。

音声入力は未来感があって、筆者はとてもワクワクするインターフェイスだと思っています!

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?