音声認識に挑戦してみましょう。
・Juliusはラズパイでも使用可能なオープンソースの音声認識エンジンです。(julius公式ページ)クラウド型ではないので、インターネットにつながなくても動作します。オープンライセンスなので個人利用はもちろん、商用でも無償で利用することができます。
・べゼリー音声対話キットに付属しているSDカードには2016年9月21日にリリースされたDictation version 4.4がインストールされています。
事前準備
・マイクとスピーカーの両方を使いますので、それぞれちゃんと機能していることを事前にご確認ください。
音声キーワード認識サンプル(sample_julius1.py)
・事前にユーザーが登録したキーワードを認識させます。決められた言葉にしか反応しませんが、高い精度で認識することができます。
実行方法
・2つの手順が必要です。まずジュリアス(音声キーワード認識版)を起動します。
1 |
$ ./boot_julius.sh |
・起動するまで数秒待ちます。
・続いて、juliusからデータを受け取って表示するpythonのプログラムを実行します。
1 |
$ python sample_julius1.py |
・マイクに向かって「こんにちは」「ありがとう」などと喋ってみてください。画面に「昼の挨拶」「感謝」など「話者の意図」が表示されたら成功です。
ソースプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
#!/usr/bin/python # -*- coding: utf-8 -*- # 音声対話デモ # for Bezelie Edgar # for Raspberry Pi # by Jun Toyoda (Team Bezelie) # from Aug15th2017 from time import sleep # ウェイト処理 import subprocess # 外部プロセスを実行するモジュール import bezelie # べゼリー専用モジュール import socket # ソケット通信モジュール import select # 待機モジュール import json # jsonファイルを扱うモジュール import csv # CSVファイルを扱うモジュール import sys # python終了sys.exit()のために必要 import re # 正規表現モジュール jsonFile = "/home/pi/bezelie/edgar/data_chat.json" # 設定ファイル ttsFile = "/home/pi/bezelie/edgar/exec_openJTalk.sh" # 音声合成 # 設定ファイルの読み込み f = open (jsonFile,'r') jDict = json.load(f) mic = jDict['data0'][0]['mic'] # マイク感度。62が最大値。 vol = jDict['data0'][0]['vol'] # スピーカー音量。 # 変数の初期化 muteTime = 1 # 音声入力を無視する時間 bufferSize = 256 # 受信するデータの最大バイト。2の倍数が望ましい。 # 関数 def socket_buffer_clear(): while True: rlist, _, _ = select.select([client], [], [], 1) if len(rlist) > 0: dummy_buffer = client.recv(bufferSize) else: break # サーボの初期化 bez = bezelie.Control() # べゼリー操作インスタンスの生成 bez.moveCenter() # サーボの回転位置をトリム値に合わせる # TCPクライアントを作成しJuliusサーバーに接続する client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) enabled_julius = False for count in range(3): try: client.connect(('localhost', 10500)) # client.connect(('10.0.0.1', 10500)) # Juliusサーバーに接続 enabled_julius = True break except socket.error, e: # print 'failed socket connect. retry' pass if enabled_julius == False: print 'Could not find Julius' sys.exit(1) # メインループ def main(): try: print '音声認識開始' subprocess.call('amixer cset numid=1 '+vol+'% -q', shell=True) # スピーカー音量 subprocess.call('sudo amixer -q sset Mic 0 -c 0', shell=True) # 自分の声を認識してしまわないように$ subprocess.call("sh "+ttsFile+" こんにちわ", shell=True) subprocess.call('sudo amixer sset Mic '+mic+' -c 0 -q', shell=True) # マイク感受性 data = "" socket_buffer_clear() while True: if "</RECOGOUT>\n." in data: # RECOGOUTツリーの最終行を見つけたら以下の処理を行う data = re.search(r'WORD\S+', data) # \s keyword = data.group().replace("WORD=","").replace("\"","") subprocess.call('sudo amixer -q sset Mic 0 -c 0', shell=True) # 自分の声を認識してしまわないよ$ print keyword subprocess.call("sh "+ttsFile+" "+keyword, shell=True) subprocess.call('sudo amixer -q sset Mic '+mic+' -c 0', shell=True) # マイク感受性を元に戻す socket_buffer_clear() data = "" # 認識終了したのでデータをリセットする else: data = data + client.recv(bufferSize) # Juliusサーバーから受信 # /RECOGOUTに達するまで受信データを追加していく except KeyboardInterrupt: # CTRL+Cで終了 client.close() bez.moveCenter() sys.exit(0) if __name__ == "__main__": main() sys.exit(0) |
終了方法
・pythonプログラムの「sample_julius1.py」は、いつものようにコントロールキー+Cキーで停止します。
・しかしjuliusはバックグラウンドで動き続けているので、これだけでは止まってはくれません。juliusを停止させるのは、ちょっと面倒です。
・まずは下記のように打ち込んで、juliusのプロセスIDを調べます。
1 |
$ check_running.sh |
・例えば以下のように表示されたとすると、juliusのプロセスIDは3923だということがわかります。
・プロセスIDが3923のプロセスを停止するには、以下のようにうちみます。
1 |
$ sudo kill 3923 |
・これで停止できたはずです。心配ならもういちどcheck_running.shを実行して、juliusが表示されないことを確認しましょう。
自然言語認識サンプル(sample_juliusNL1.py)
・単語だけでなく、普通に喋った言葉をjuliusが文字に変換してくれます。言語モデルの学習など手をかければ精度は上がるはずですが、初期状態ではよく使う表現しか認識してくれません。
実行方法
・やはり2つの手順が必要です。まずジュリアス(自然言語認識版)を起動します。
1 |
$ ./boot_juliusNL.sh |
・数秒待ってから、juliusからデータを受け取って表示するpythonのプログラムを起動します。
1 |
$ python sample_juliusNL1.py |
・好きな言葉を喋ってみてください。ありふれた言葉以外は、正しく認識されないと思います。
ソースプログラム
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
#!/usr/bin/python # -*- coding: utf-8 -*- # Julius音声認識(自然言語版)サンプル # for Bezelie Edgar # for Raspberry Pi # by Jun Toyoda (Team Bezelie) # from Aug15th2017 from time import sleep # ウェイト処理 import subprocess # 外部プロセスを実行するモジュール import bezelie # べゼリー専用モジュール import socket # ソケット通信モジュール import select # 待機モジュール import json # jsonファイルを扱うモジュール import csv # CSVファイルを扱うモジュール import sys # python終了sys.exit()のために必要 import re # 正規表現モジュール import xml.etree.ElementTree as ET # XMLエレメンタルツリー変換モジュール jsonFile = "/home/pi/bezelie/edgar/data_chat.json" # 設定ファイル ttsFile = "/home/pi/bezelie/edgar/exec_openJTalk.sh" # 音声合成 # 設定ファイルの読み込み f = open (jsonFile,'r') jDict = json.load(f) mic = jDict['data0'][0]['mic'] # マイク感度。62が最大値。 vol = jDict['data0'][0]['vol'] # スピーカー音量。 # 変数の初期化 muteTime = 1 # 音声入力を無視する時間 bufferSize = 256 # 受信するデータの最大バイト。2の倍数が望ましい。 # 関数 def socket_buffer_clear(): while True: rlist, _, _ = select.select([client], [], [], 1) if len(rlist) > 0: dummy_buffer = client.recv(bufferSize) else: break # TCPクライアントを作成しJuliusサーバーに接続する client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) enabled_julius = False for count in range(3): try: client.connect(('localhost', 10500)) # client.connect(('10.0.0.1', 10500)) # Juliusサーバーに接続 enabled_julius = True break except socket.error, e: # print 'failed socket connect. retry' pass if enabled_julius == False: print 'Juliusが起動していないようです' sys.exit(1) # メインループ def main(): try: subprocess.call('amixer cset numid=1 '+vol+'% -q', shell=True) # スピーカー音量 subprocess.call('sudo amixer -q sset Mic 0 -c 0', shell=True) # 自分の声を認識してしまわない $ subprocess.call("sh "+ttsFile+" 音声認識開始", shell=True) sleep (muteTime) subprocess.call('sudo amixer sset Mic '+mic+' -c 0 -q', shell=True) # マイク感受性 socket_buffer_clear() print 'ー何か喋ってくださいー' data = "" while True: if "</RECOGOUT>\n." in data: # RECOGOUTツリーの最終行を見つけたら以下の処理を行う try: # dataから必要部分だけ抽出し、かつエラーの原因になる文字列を削除する。 data = data[data.find("<RECOGOUT>"):].replace("\n.", "").replace("</s>","").replace("<s>","") # fromstringはXML文字列からコンテナオブジェクトであるElement型に直接変換する。 root = ET.fromstring('<?xml version="1.0" encoding="utf-8" ?>\n' + data) keyword = "" for whypo in root.findall("./SHYPO/WHYPO"): keyword = keyword + whypo.get("WORD") subprocess.call('sudo amixer -q sset Mic 0 -c 0', shell=True) # 自分の声を認識してしま$ print keyword subprocess.call("sh "+ttsFile+" "+keyword, shell=True) sleep (muteTime) socket_buffer_clear() subprocess.call('sudo amixer -q sset Mic '+mic+' -c 0', shell=True) # マイク感受性を元に戻す print "ー何か喋ってくださいー" except: print "----- except -----" data = "" # 認識終了したのでデータをリセットする else: data = data + client.recv(bufferSize) # Juliusサーバーから受信 # /RECOGOUTに達するまで受信データを追加していく except KeyboardInterrupt: # CTRL+Cで終了 client.close() sys.exit(0) if __name__ == "__main__": main() sys.exit(0) |
解説
・18行目でimportしているElementTreeは、juliusから送られてきたxmlを解釈するために利用しているモジュールです。