【Raspberry PI】Julius + Open JTalkで非ネット環境でのなんちゃってAIスピーカー

■ はじめに

https://blogs.yahoo.co.jp/dk521123/37449064.html
https://blogs.yahoo.co.jp/dk521123/37451114.html
の続き。
更に、以下の関連記事で行ったOpen JTalkを組み合わせて
非ネット環境でのなんちゃってAIスピーカー的なことをやってみる。
https://blogs.yahoo.co.jp/dk521123/37367963.html

■ 環境設定

必要なモジュールを組みこむ

# snd-pcm-ossモジュールを組み込む
#  => これやらんとPython実行時に「failed to begin input stream」と言われる
sudo modprobe snd-pcm-oss

■ 文法ファイル作成

 * Juliusの環境作成や作り方は、以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/37451114.html

【任意:確認用モジュール】hello.py

python hello.py」で「御用でしょうか?」って言ったらOK
# coding:utf-8

import openJTalk

def main():
    openJTalk.openJTalk("御用でしょうか?")

if __name__ == "__main__":
    main()

hello_raspi.yomi

% CALL
ねぇ     ねぇ
ハロー   はろー
% NAME
ラズパイ らずぱい
% NOW
今       いま
% TODAY
今日     きょう
% WA
は       は
% ASK_TIME
何時     なんじ
% ASK_DAY
何日     なんにち
何曜日   なんようび
% NS_B
[s]     silB
% NS_E
[s]     silE

hello_raspi.grammar

S      : NS_B CALL NAME NS_E
S      : NS_B ASK_TIME_ NS_E
S      : NS_B ASK_DAY_ NS_E
ASK_TIME_ : NOW ASK_TIME
ASK_TIME_ : NOW WA ASK_TIME
ASK_DAY_ : TODAY ASK_DAY
ASK_DAY_ : TODAY WA ASK_DAY

生成するためのコマンド

iconv -f utf8 -t eucjp ~/hello_raspi.yomi | yomi2voca.pl | iconv -f eucjp -t utf8 > ~/hello_raspi.voca
~/julius/gramtools/mkdfa/mkdfa.pl hello_raspi

# テスト (Ctrl + Cで終了)
julius -C julius-kits/grammar-kit-4.3.1/hmm_mono.jconf -input mic -gram hello_raspi -nostrip

■ サンプル

openJTalk.py

 * 以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/37367963.html

start-julius.sh

作成後は、「./start-julius.sh」でテストしておくといいかも(プロセスIDが表示され、2秒後終了する。「kill -9 【プロセスID】」しておくこと)
#!/bin/sh

# -module : juliusをモジュールモードで実行 / > /dev/null : 標準出力は捨てる
julius -C julius-kits/grammar-kit-4.3.1/hmm_mono.jconf -input mic -gram hello_raspi -module > /dev/null &

#プロセスIDを出力
echo $!

sleep 2

hello_raspi.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import socket
import subprocess
import time
import datetime
import openJTalk 

julius_host = 'localhost'
julius_port = 10500
day_of_week = ["月","火","水","木","金","土","日"]

has_recongized = False

def process_query(sentence):
   global has_recongized

   if has_recongized == False:
      if sentence in ["ねぇラズパイ", "ハローラズパイ"]:
         print("Tell me, Ras-pi")
         openJTalk.openJTalk("御用でしょうか?")
         has_recongized = True
   else:
      if sentence in ["ねぇラズパイ", "ハローラズパイ"]:
         print("Hey Ras-pi")
         openJTalk.openJTalk("はい")
      elif sentence in ["今何時", "今は何時"]:
         print("What time?")
         answer_for_what_time = str(datetime.datetime.today().strftime('%H時%M分')) + "です"
         print(answer_for_what_time)
         openJTalk.openJTalk(answer_for_what_time)
      elif sentence in ["今日何日", "今日は何日"]:
         print ("What date?")
         answer_for_what_date = str(datetime.datetime.today().strftime('%Y年%m月%d日')) + "です"
         print(answer_for_what_date)
         openJTalk.openJTalk(answer_for_what_date)
      elif sentence in ["今日何曜日", "今日は何曜日"]:
         print ("What day of the week?")
         answer_for_what_week = "今日は" + day_of_week[datetime.datetime.today().weekday()] + "曜日です"
         print(answer_for_what_week)
         openJTalk.openJTalk(answer_for_what_week)
      else:
         print("do not understand...")
         openJTalk.openJTalk("すみません。良く分かりません。")

# Main関数
def main():
    # julius起動スクリプトを実行
    process = subprocess.Popen(["./start-julius.sh"], stdout=subprocess.PIPE, shell=True)
    # juliusのプロセスIDを取得
    pid = str(process.stdout.read().decode('utf-8'))
    # 3秒間スリープ
    time.sleep(3)

    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # サーバモードで起動したjuliusに接続
    client.connect((julius_host, julius_port))
    print("<<please speak>>")

    try:
        data = ''
        sentence =''

        while True:
            if '</RECOGOUT>\n.' in data:
               word = ""
               for line in data.split('\n'):
                 index = line.find('WORD="')
                 if index != -1:
                     line = line[index + 6:line.find('"', index + 6)]
                     word = str(line)
                 if word != '[s]':
                    sentence += word

               print ('"' + sentence + '"')
               process_query(sentence)
               sentence = ''
               data = ''
               print ("<<<please speak>>>")
            else:
               data += str(client.recv(1024).decode('utf-8'))
    except KeyboardInterrupt:
        # 起動スクリプトのプロセスを終了
        process.kill()
        # juliusのプロセスを終了する。
        subprocess.call(["kill " + pid], shell=True)
        client.close()

if __name__ == "__main__":
    main()

■ 実行

python hello_raspi.py」で実行する
$ python hello_raspi.py 
<<please speak>>
"ハローラズパイ" << 「ハローラズパイ」ってマイクに向かって言った
Tell me, Ras-pi
<<<please speak>>>
"今何時"         << 「今何時」ってマイクに向かって言った
What time?
23時13分です
<<<please speak>>>
"今日何日"         << 「今日何日」ってマイクに向かって言った
What date?
2018年03月26日です
<<<please speak>>>
"今日何曜日"       << 「今日何曜日」ってマイクに向かって言った
What day of the week?
今日は月曜日です
<<<please speak>>>

■ トラブル

 * 以下の関連記事を参照のこと。
https://blogs.yahoo.co.jp/dk521123/37459347.html