Linux
shell
Julius
Python3
Raspberrypi3

Raspberry piで音声認識(julius)を使用して特定の言葉に反応

Raspberry piで音声認識(julius)を使用して特定の言葉に反応

前提条件

  • こちらまでできていることを前提で進んで行きます。

最初に、juliusをmoduleモードで実行し、juliusのプロセスIDを取得するシェルスクリプトを作成します。

julius-start.sh
#!/bin/sh

julius -C ~/julius-4.4.2/julius-kit/dictation-kit-v4.3.1-linux/word.jconf -module > /dev/null &
echo $! #プロセスIDを出力
sleep 2 #2秒間スリープ
  • -module
    • juliusをモジュールモードで実行します。
  • > /dev/null
    • 標準出力は捨てます。
  • &> /dev/null
    • > /dev/nullの前に&をつけると標準出力と標準エラーを捨てます。今回はエラーが見えた方が良いと思いますのでエラーは捨てません。
  • echo $!
    • プロセスIDを出力.

julius-start.shの実行

./ julius-start.sh

プロセスIDが出力されて数秒後終了すると成功です。

次に、特定の言葉に対してリアクションを返すpythonプログラム
今回は音声ファイルを再生するようにします。
julius-start.shと同ディレクトリにvoice.pyを作成します。

voice.py
import socket
import xml.etree.ElementTree as ET
import os
import subprocess
import time

host = '127.0.0.1' #localhost
port = 10500   #julisuサーバーモードのポート

def main():

    p = subprocess.Popen(["./julius-start.sh"], stdout=subprocess.PIPE, shell=True) # julius起動スクリプトを実行
    pid = str(p.stdout.read().decode('utf-8')) # juliusのプロセスIDを取得
    time.sleep(3) # 3秒間スリープ
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((host, port)) #サーバーモードで起動したjuliusに接続

    try:
        data = '' # dataの初期化
        killword ='' # 前回認識した言葉を記憶するための変数
        while 1:
            #print(data) # 認識した言葉を表示して確認
            if '</RECOGOUT>\n.' in data: 

                root = ET.fromstring('<?xml version="1.0"?>\n' + data[data.find('<RECOGOUT>'):].replace('\n.', ''))
                for whypo in root.findall('./SHYPO/WHYPO'):

                    word = whypo.get('WORD')# juliusで認識したWORDをwordに入れる
                    if word == u'こんにちは':
                        if killword != ('こんにちは'):
                            os.system("aplay '/home/pi/Music/konnichiwa.wav'")# 音声ファイルを再生
                            killword = ('こんにちは')

                    elif word == u'おはよう':
                        if killword != ('おはよう'):
                            os.system("aplay '/home/pi/Music/ohayo.wav'")
                            killword = ('おはよう')

                    elif word == u'こんばんは':
                        if killword != ('こんばんは'):
                            os.system("aplay '/home/pi/Music/konbanwa.wav'")
                            killword = ('こんばんは')

                    elif word == u'ばいばい':
                        if killword != ('ばいばい'):
                            os.system("aplay '/home/pi/Music/bye.wav'")
                            killword = ('ばいばい')

                    elif word == u'せもぽぬめ':
                        os.system("aplay '/home/pi/Music/secret.wav'")
                        killword = ('シークレット')

                    elif word == u'おやすみ':
                        os.system("aplay '/home/pi/Music/oyasumi.wav'")
                        killword = ('おやすみ')

                    else:
                        os.system("aplay '/home/pi/Music/name.wav'")
                        killword = ('name')
                    print (word) # wordを表示
                    data = '' # dataの初期化

            else:
                data += str(client.recv(1024).decode('utf-8')) #dataが空のときjuliusからdataに入れる
                print('NotFound')# juliusに認識する言葉がない。認識していない。


    except KeyboardInterrupt:
        p.kill()
        subprocess.call(["kill " + pid], shell=True)# juliusのプロセスを終了する。
        client.close()

if __name__ == "__main__":
    main()

XMLでエラー出るって話聞いたのでXMLを使わない方法で・・・

voice2.py
# -*- coding: utf-8 -*-
import subprocess
import socket
import string
import os
import random
import numpy as np
from numpy.random import *
import time

host = "localhost"
port = 10500

p = subprocess.Popen(["./julius_start.sh"], stdout=subprocess.PIPE, shell=True)
pid = str(p.stdout.read().decode('utf-8')) # juliusのプロセスIDを取得
time.sleep(5)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

data =""
killword =""

while True:

    while (1):
        if '</RECOGOUT>\n.' in data:
            #data = data + sock.recv(1024)
             strTemp = ""
            for line in data.split('\n'):
                index = line.find('WORD="')
                if index != -1:
                    line = line[index+6:line.find('"',index+6)]
                    strTemp += str(line)

                if strTemp == 'バイバイ':
                    if killword != 'バイバイ':
                        print ("Result: " + strTemp)
                        os.system("aplay '/home/pi/Music/byebye.wav'")
                        print ("<<<please speak>>>")
                        killword = "バイバイ"

                elif strTemp == 'おはよう':
                    if killword != 'おはよう':
                        print ("Result: " + strTemp)
                        os.system("aplay '/home/pi/Music/ohayo.wav'")
                        print ("<<<please speak>>>")
                        killword = "おはよう"

                elif strTemp == 'こんにちは':
                    if killword != "こんにちは":
                        print ("Result: " + strTemp)
                        os.system("aplay '/home/pi/Music/konnichiwa.wav'")
                        print ("<<<please speak>>>")
                        killword = "こんにちは"

                elif strTemp == 'こんばんは':
                    if killword != "こんばんは":
                        print ("Result: " + strTemp)
                        os.system("aplay '/home/pi/Music/konbanwa.wav'")
                        print ("<<<please speak>>>")
                        killword = "こんばんは"

                elif strTemp == 'こんばんは':
                    if killword != "こんばんは":
                        print ("Result: " + strTemp)
                        os.system("aplay '/home/pi/Music/konbanwa.wav'")
                        print ("<<<please speak>>>")
                        killword = "こんばんは"

                else:
                    print("Result:" + strTemp)
                    i = randint(3)
                    if i == 0:
                        os.system("aplay: '/home/pi/Music/aizuchi00.wav'")
                    elif i == 1:
                        os.system("aplay: '/home/pi/Music/aizuchi01.wav'")
                    elif i == 2:
                        os.system("aplay: '/home/pi/Music/aizuchi02.wav'")
                    print ("<<<please speak>>>")
                data = ""
  else:
            data += str(sock.recv(1024).decode('utf-8'))

まとめ

今回はwavを再生するようにしましたが、テレビのon,offや部屋の明かりon,offなど声でできるようにすると面白しろそうですね。
また、パターンが少ないので簡単なif文で書きましたが、量が多くなると面倒なのでその場合はDBを使う用にすると良いと思います。
DBを使用するといろいろ応用できます。
また、whypo.get('WORD')はWORDではないものもgetすることができます。
それはjuliusのmoduleモードについてを参照すると良いでしょう。