Mrhappyの旅する人応援ブログ

~旅行情報を中心にhappyの書きたいことを発信していきます~

JuliusとNode-Redを使ってRaspberry piで音声認識をする。

どうもこんにちは、Mrhappyです。今日は趣味で始めたラズベリーパイを使った音声認識の方法をご紹介します。というのもhappyが音声認識を実行できるようになるために非常に多くの苦労があったため、これから挑戦しようとする方のために、共有しておきたいと思ったからです。

ネットで検索すると音声認識に関する記事は散見されましたが、今回happyが行ったような方法で行っている方がおられなかったので、参考になればと思います。

 これまでの経緯

音声認識を使って認識した言葉を元にNode-Redを使っていろいろと処理したいなと思ってやろうとしたんですけど、happyはpythonは使えるのですがjavaがさっぱりわかりません。しかしNode-Redの中で使える言語がjavaしかなく、Juliusから出力されたデータをNode-Red内で処理できないので、外部でpythonを使ってテキストを抽出してからNode-Redに投げるという作戦を考えました。

 結論から言うと

やったこととしては、

  1. Juliusをモジュールモードで起動し、pythonのプログラムでJuliusの吐き出すデータにソケット通信でアクセスする。
  2. Juliusから出力されるデータは、テキストデータ以外にもいろいろ含まれているので、pythonのプログラムを使って、そのデータからテキスト部分だけを抜き出す。
  3. 抜き出したテキストをソケット通信を使ってNode-Redに送信。 

 Juliusをmoduleモードで起動

まずはJuliusを起動します。moduleモードで起動することにより、外部プログラムからアクセスすることが出来ます。LXterminalに以下のコマンドを入力します。

~/julius/julius-4.4.2.1/julius/julius -C ~/julius/julius-kit/dictation-kit-v4.4/main.jconf -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -module

 

 Nioe-Redの設定

最後にpythonのプログラムからテキストデータを受け取るNode-Redのノードを設定します。

f:id:Mrhappy:20200630151616j:plain

ノードはこのように配置しました。グレーのノードがpythonからテキストを受け取るためのノードです。ノード一覧の「tcp in」に相当します。その他、深緑のノードは送信されてくるテキストをデバッグウインドウに表示するためのもの、黄緑色もノードはIBMのWatsonのノードで、テキストを音声に変換する「text to speech」というノードです。このノードはデフォルトでは入っていませんので、ご自身で追加をお願いします。ピンク色のノードは音を出すためのノードです。

f:id:Mrhappy:20200630151612j:plain

tcp inのノードは上のように設定します。ポート番号をpythonプログラムのport1と一致させてください。

 Juliusから読み取ったデータから言葉だけを抽出してNode-Redに渡すプログラム

Juliusからデータを受け取って、テキストを抽出してからNode-Redに投げるpythonのプログラムです。IPアドレス127.0.0.1は自分自身を指します。port1の5000という数字は任意に変更していただいて構いません。port2のJuliusのポートは10500で固定されていますので、変更することはできません。(詳しい人ならできるかもしれないけど必要ないよね笑)

つまり、port2経由でJuliusからデータを受け取って、port1経由でNode-Redにテキストを送信してます。

# -*- coding:utf-8 -*-
import socket

host = '127.0.0.1'   # IPアドレス
port1 = 5000          #適当なPORTを指定してあげます
port2 = 10500         # Juliusとの通信用ポート番号

# Node-redにソケット通信で接続
client1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #オブジェクトの作成をします
client1.connect((host, port1)) #これでサーバーに接続します
# Juliusにソケット通信で接続
client2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client2.connect((host, port2))

data = ""
try:
    data = ""
    while True:
        if '\n.' in data:
            # 出力結果から認識した単語を取り出す
            recog_text = ""
            for line in data.split('\n'):
                index = line.find('WORD="')
                if index != -1:
                    line = line[index+6:line.find('"', index+6)]
                    recog_text = recog_text + line
            print("認識結果: " + recog_text)
            client1.send(recog_text.encode('utf-8')) #適当なデータを送信します(届く側にわかるように)
            data =""
        else:
            data += str(client2.recv(1024).decode('utf-8'))
            print('NotFound')
except KeyboardInterrupt:
    print('finished')
    client2.send("DIE".encode('utf-8'))
    client1.close()
    client2.close()

ここまできたら、Juliusを起動⇒Node-Redのデプロイ⇒pythonプログラムの実行という順番で実行してください。Juliusとpythonのプログラムは別々のLXterminalを開いて実行してください。

 まとめ

いかがだったでしょうか。happyはraspberry piを触り始めて間もないのでこのような回りくどい方法に頼らざるを得ませんでした。Javaが使える人はわざわざpythonを経由しなくてもNode-Red内のfunctionノードの中に処理を書いた方が軽量で早いでしょう。「text to speech」ノードはIBM Cloudというサイトにアカウントを作って認証情報を作成する必要がありますが、個人利用のレベルでは無料プランで十分対応できると思いますので、利用してみてください。