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''メソッドを呼び出します。