eSEATコンポーネントのアクティベーション後の振舞
初期化プロセスのところでも記述していますが、eSEATコンポーネントのアクティベーション後に有効になるのは、RTCのポート(rctin, rtcout, provider, consumer)からの入出力です。それ以外のもの(GUIとWebアダプタ)は、下記に記載している「stateのルールに基づく反応処理」を実行しています。
eSEATでは、外部からのデータ入力として、RTCのデータポート(rtcin)、サービスポート(Provider)、Webアダプタ(web)およびGui部品からの4通りの入力経路があります。
- Gui部品からの入力の場合は、各部品のイベント処理から直接起動されています。
- サービスポート(Provider)の場合には、定義した実装関数が直接コールされるようになています。
- Webアダプタの場合には、'/rct_onData', '/rtc_processResult', '/evalCommand'の3つの方法でeSEATの内部メソッドの呼び出しを行っています。特に、'/rtc_onData'と'/rtc_processResult'は、それぞれ onDataメソッドとprocessResultメソッドを呼出しを行っており、データポートからの入力とほぼ同じような振舞いをします。
以下では、eSEATのデータポートからの入力に対するstateのルールに基づく反応処理の実行の詳細について記述していきます。
stateのルールに基づく反応処理
内部処理が呼ばれるタイミング
通常のRTCでは、データポートからの入力を周期実行されるonExecuteメソッドの中で処理を行っています。
しかし、eSEATは対話制御を目的として開発されていたため、周期的な処理の中で入力データに対する反応処理を行うのではなく、eSEATDataListenserクラスがデータ入力ポート(rtcin)に関連付けることで直接内部メソッドの呼び出しを行っています。
データポートからの入力は、入力バッファを経由せず、直接onDataメソッドを呼出しています。
onDataメソッド内の処理
onDataメソッドは、eSEATクラスに実装されています。このメソッドは、Webアダプタからも呼び出されますので、コンポーネント内部変数 self.activatedをチェックし、この変数が真の時(RTCがアクティベート状態にある時)のみ処理を実行しています。
RTCがアクティベートされていれば、データポートからの入力dataの型に応じて下記のような動作を行います。
- dataがTimedStringの時
- 入力されたデータ型がTimedStringの時には、まず、文字列データdata.dataをUTF-8に変換
- data.dataが音声認識システムからのデータだと判断し、 eSEAT_Core.processResultを実行
- 上記の処理でが偽を返したとき(音声認識の結果ではないと判断された時) eSEAT_Core.processOnDataInを実行
- dataがTimedWStringの時
- data.dataが音声認識システムからのデータだと判断し、 eSEAT_Core.processResultを実行
- 上記の処理でが偽を返したとき(音声認識の結果ではないと判断された時) eSEAT_Core.processOnDataInを実行
- 上記以外のすべてeSEAT_Core.onDataを実行
eSEAT_Core.onDataの処理
eSEAT_Core.onData内部では、まず与えられたデータdataが文字列かどうかを判断します。この処理は、データポートからの入力ではほとんど起こらないのですが、Webアダプタからの入力に対応するためのコードになります。
- 入力されたデータdataが文字列の場合には、WebAdaptor.pyの
parseDataparseQueryString関数を呼出し、データ変換した結果をdata2にセットし、data2が空でなければ processDataIn(name, data2)を実行します。data2が空の場合には、processResultを呼び出し音声認識のデータと仮定し処理を行い、失敗すれば(processResultからの返り値が Falseであれば) processOnDataInメソッドを呼び出します。これは、前述の「onDataメッソド内の処理」におけるTimedWStringの場合と同様な処理です。 - 入力されたデータdataが文字列以外のときには、processOnDataInメソッドを呼び出します。
上記のように、eSEATのメインの処理は、eSEAT_Coreの processResultメソッドとprocessOnDataInメソッドになることがわかると思います。
eSEAT_Core.processResultの処理
- data が <?xmlから始まる文字列である。すなわちJuliusRTCからのデータである場合procesJuliusResult(name, data)を実行し、その結果(コマンド列)を cmdsにセット
- 上記以外うの場合lookupWithDefault(self.currentstate, name, data)を実行し、その結果(コマンド列)をcmdsにセット
- cmdsが空であれば、ログにメッセージを書き出し、偽を返す。
- cmdsに格納されたコマンド cmd の
それぞれに対し、self.activateCommand(cmd, data)executeメソッドを実行する - コマンドの実行終了後、真を返す。
eSEAT_Core.processOnDataInの処理
- lockupWithDefault(self.currentstate, name, "ondata")を呼び出し、その結果(コマンド列)をcmdsにセット
- cmdsが空の場合には、logにメッセージを出力し、偽を返す。
- cmdsに格納されたコマンド cmd のそれぞれに対し、以下の処理を行う
- cmd[0]をkondにセット
- グローバル変数、seat, rtc_in_data, julius_resultに対し、
- seat = self
- rtc_in_data = data
- julius_data = None とする
- kond[0]の値がセットされていた場合、その名前のファイルが存在すれば、そのスクリプトを実行する
- kond[1]を評価(eval)し、真であれば cmd[1]の
配列の各要素cに対して self.activateCommandEx(c, data)を呼び出す。executeメソッドを呼び出して実行する
- 上記の処理終了後、真を返す
activateCommandの処理 (2017-11-22、この処理はTaskクラスのexecuteメソッドに置き換えられました)
activateCommandメソッドでは、第一引数で与えられた配列に応じて、applyMessage, applyLog, applyShell, applyScript, applyTransitionを呼び出します。各メソッドの機能は、下の通りです。
メソッド | 機能 |
---|---|
applyMessage | 対応したアダプタにメッセージを送信する |
applyLog | ログに出力する |
applyShell | subprocess.Popenでシェルを実行し、その結果を指定アダプタに出力する |
applyScript | exec関数で指定されたスクリプトを実行し、rtc_resultに値があれば指定アダプタに出力する |
applyTransition | eSEATの内部状態遷移を起こす |
activateCommandExの処理 (2017-11-22、この処理はTaskクラスのexecuteExメソッドに置き換えられました)
activateCommandExメソッドでは、第一引数で与えられた配列の最初の要素が 'c'のときその4番目の要素をNoneにセットし、activateCommandメソッドを呼び出します。