質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Julius

Julius は,音声認識システムの開発・研究のためのオープンソースの高性能な汎用大語彙連続音声認識エンジンです。数万語彙の連続音声認識を一般のPCやスマートフォン上でほぼ実時間で実行できる軽量さとコンパクトさを持っています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

3393閲覧

Juliusを使用したGUIアプリケーション(音声認識を使ったクイズ)を作成したい。

dice1989

総合スコア2

Julius

Julius は,音声認識システムの開発・研究のためのオープンソースの高性能な汎用大語彙連続音声認識エンジンです。数万語彙の連続音声認識を一般のPCやスマートフォン上でほぼ実時間で実行できる軽量さとコンパクトさを持っています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/05/21 06:39

前提・実現したいこと

Juliusを使用したGUIアプリケーションを作成しています。
最終目標は、問題をGUIに表示→音声で入力→正解・不正解を表示といったアプリを作成したいと考えています。
その途中段階で、
スタートボタンをクリック→Juliusをモジュールモードで起動→出力結果をTCP/IP経由で取得・GUIに表示
まで作成しました。
次のステップとして
ストップボタンをクリック→Juliusとの接続を停止させる
を実現したいのですが、以下のソースコードすとストップボタンが押される。次の
音声入力が行われると接続が停止されるという状態しか作れませんでした。
停止ボタンが押されたら即接続を停止させたいのですが、どういった方法がありますでしょうか。
ご教示いただければ幸いです。

発生している問題

ストップボタンが押されてから即接続を停止できない。

該当のソースコード

python3+Julius

1# -*- coding: utf-8 -*- 2 3import tkinter # Tkinterモジュールのインポート 4import socket 5import string 6import subprocess 7import time 8import threading 9 10stopFlag = 0 11 12# コンソールに"Button is clicked."を出力する関数 13def startButtonClicked(): 14 # ボタン非表示化 15 #startButton.pack_forget() 16 # スレッディング処理 17 thread1 = threading.Thread(target=juliusWork) 18 thread1.start() 19 20def stopButtonClicked(): 21 #stopButton.pack_forget() 22 global stopFlag 23 stopFlag = 1 24 print("stop") 25 26def juliusWork(): 27 28 #Juliusをモジュールモードで起動(自作辞書使用) 29 p = subprocess.Popen("julius -C ~/julius/dictation-kit-4.5/am-gmm.jconf -nostrip -gram ~/julius/test/test -input mic -module", stdout=subprocess.PIPE, shell=True) 30 print('Initiating') 31 time.sleep(2) 32 print('Done') 33 pid = str(p.pid) 34 print(pid) 35 36 host = 'localhost' # IPアドレス 37 port = 10500 # juliusの待ち受けポート 38 39 # TCP/IPで、juliusサーバに接続 40 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 41 sock.connect((host, port)) 42 43 data = "" 44 while True: 45 #stopFlagが立った時の終了処理 46 global stopFlag 47 if stopFlag == 1: 48 print("finished") 49 sock.close() 50 stopFlag = 0 51 break 52 53 # 音声認識結果のみをXMLで取得 54 while (data.find("</RECOGOUT>\n.") == -1): 55 soc = sock.recv(1024) 56 data = data + soc.decode('utf-8') 57 58 # 音声認識結果のXMLから単語部分のみを抜き出して連結 59 recog_text = "" 60 for line in data.split('\n'): 61 index = line.find('WORD="') 62 if index != -1: 63 line = line[index+6:line.find('"', index+6)] 64 if line != "[s]" and line != "[/s]": 65 recog_text = recog_text + line 66 67 print("認識結果: " + recog_text) 68 69 resultTextWidget.insert('end', "認識結果=" + recog_text+"\n") #テキストフィールドに検出結果を表示 70 data = "" #dataの中身(検出結果)を空に 71 72# ウィンドウ(フレーム)の作成 73root = tkinter.Tk() 74# ウィンドウの名前を設定 75root.title("demo_Tkinter") 76# ウィンドウの大きさを設定 77root.geometry("400x400") 78 79resultTextWidget = tkinter.Text(root) 80resultTextWidget.pack() 81 82# ボタンの作成(text=ボタンに表示されるテキスト, command=押下時に呼び出す関数) 83startButton = tkinter.Button(root, text="スタート", command=startButtonClicked) 84startButton.pack()# ボタンの表示 85stopButton = tkinter.Button(root, text="ストップ", command=stopButtonClicked) 86stopButton.pack()# ボタンの表示 87 88# イベントループ 89root.mainloop()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

下の3行目で、音声データが来るまでスレッドがブロックされてしまっていることが原因ではないでしょうか。

# 音声認識結果のみをXMLで取得 while (data.find("</RECOGOUT>\n.") == -1): soc = sock.recv(1024)

解決策として、
1.

def stopButtonClicked(): #stopButton.pack_forget() global stopFlag stopFlag = 1 print("stop")

の中で、ストップボタンが押されたらsockにダミーのデータを送るようにする。
(sockをグローバル変数にする等、何らかの組み換えが必要)

2.

sock.settimeout(value)

として、ソケットにタイムアウトを設定し、タイムアウト例外が発生したらループを回すようにする。

https://docs.python.org/ja/3/library/socket.html#socket.socket.settimeout

3. sockをノンブロッキングモードにして全面的に作り変える。

等が考えられます。

投稿2020/05/21 10:58

編集2020/05/21 10:59
patapi

総合スコア820

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dice1989

2020/05/21 11:58 編集

教えていただいた解決策2で希望の動作を実現することができました。 ありがとうございます。解決策1や3についても勉強したいと思います。 複数の解決策をご提案いただき大変助かりました。 以下に、修正したソースコードを載せます(正しいでしょうか?)。 # -*- coding: utf-8 -*- import tkinter # Tkinterモジュールのインポート import socket import string import subprocess import time import threading stopFlag = False # コンソールに"Button is clicked."を出力する関数 def startButtonClicked(): # ボタン非表示化 #startButton.pack_forget() # スレッディング処理 thread1 = threading.Thread(target=juliusWork) thread1.start() def stopButtonClicked(): #stopButton.pack_forget() print("stop") global stopFlag stopFlag = True def juliusWork(): #Juliusをモジュールモードで起動(自作辞書使用) p = subprocess.Popen("julius -C ~/julius/dictation-kit-4.5/am-gmm.jconf -nostrip -gram ~/julius/test/test -input mic -module", stdout=subprocess.PIPE, shell=True) print('Initiating') time.sleep(2) print('Done') #pid = str(p.pid) #print(pid) host = 'localhost' # IPアドレス port = 10500 # juliusの待ち受けポート # TCP/IPで、juliusサーバに接続 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) data = "" while True: try: sock.settimeout(1) # 音声認識結果のみをXMLで取得 while (data.find("</RECOGOUT>\n.") == -1): soc = sock.recv(1024) data = data + soc.decode('utf-8') # 音声認識結果のXMLから単語部分のみを抜き出して連結 recog_text = "" for line in data.split('\n'): index = line.find('WORD="') if index != -1: line = line[index+6:line.find('"', index+6)] if line != "[s]" and line != "[/s]": recog_text = recog_text + line print("認識結果: " + recog_text) resultTextWidget.insert('end', "認識結果=" + recog_text+"\n") #テキストフィールドに検出結果を表示 data = "" #dataの中身(検出結果)を空に except Exception as e: global stopFlag print(stopFlag) if stopFlag: sock.close() p.kill() stopFlag = False break # ウィンドウ(フレーム)の作成 root = tkinter.Tk() # ウィンドウの名前を設定 root.title("demo_Tkinter") # ウィンドウの大きさを設定 root.geometry("400x400") resultTextWidget = tkinter.Text(root) resultTextWidget.pack() # ボタンの作成(text=ボタンに表示されるテキスト, command=押下時に呼び出す関数) startButton = tkinter.Button(root, text="スタート", command=startButtonClicked) startButton.pack()# ボタンの表示 stopButton = tkinter.Button(root, text="ストップ", command=stopButtonClicked) stopButton.pack()# ボタンの表示 # イベントループ root.mainloop()
patapi

2020/05/21 11:59

OKと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問