#BaseQiChatExecutor's profile🎙
BaseQiChatbotExecutorを実装すると、QiChatのTopicファイル中の^executeで呼び出すことができます。
一見Bookmarkのような機能ですがBookmarkとは異なり、順番に処理を実行できます🟥🟧🟨🟩🟦🟪例えば「ダンスをします」と言ってから実際にダンスのアニメーションを実行し、ダンスが終わったら「如何でしたか?」と発話させる、といった内容をTopicファイル上で記述できるようになります。
#習いながら慣れてみる⌨️🔁
以下の内容はGitのMastering Executeで体験できるものです。
ここではTopicファイルを次のように変身🌜🧹させています。
topic: ~execute()
concept:(dance_request) [踊ってみせて 踊ってほしい]
proposal: %execute_proposal 静かな夜景は贅沢ですね
u:(~dance_request) 見ていてください ^execute(myExecutor,param1) 今夜は月が綺麗です
会話中に^executeへ到達するとExecutorのrunWithメソッドが呼ばれ、引数がListで渡されます。
キー名はmyExecutorで、パラメータは好きな数だけ設定することが可能です。不可説不可説転は不可能
#QiChatExecutorクラスの生誕🧁👑
BaseQiChatExecutorからMyQiChatExecutorクラスを作成し、runWithとstopを実装します💅💫
ここではコードの書き方に注意が必要です👀
例えば、以下のコードを見てみましょう。
class MyQiChatExecutor extends BaseQiChatExecutor {
protected MyQiChatExecutor(QiContext context) {
super(context);
}
@Override
public void runWith(List<String> params) {
//アニメーションのオブジェクトを作成
Animation animation =
AnimationBuilder.with(getQiContext())
.withResources(R.raw.taichichuan_a001).build();
//アクションをビルド
Animate animate =
AnimateBuilder.with(getQiContext())
.withAnimation(animation).build();
//アニメーション開始時に"Animation started."とログを出す
Log.i(TAG, "Animation started."
, ConversationItemType.INFO_LOG)
//アクションを実行
animate.run()
//アニメーション終了時に"Animation finished."とログを出す
Log.i(TAG, "Animation finished."
, ConversationItemType.INFO_LOG)
}
@Override
public void stop() {
//Executeが実行中にChatがキャンセル、もしくは停止された時にコール
Log.i(TAG, "QiChatExecutor stopped");
}
このコードでは、アニメーション中にチャットが終了してもアニメーションをキャンセルすることができません。これはアニメーションが非同期処理になっていないためです。
それでは、次のコードはどうでしょう。
class MyQiChatExecutor extends BaseQiChatExecutor {
private Future<Void> future = null;
protected MyQiChatExecutor(QiContext context) {
super(context);
}
@Override
public void runWith(List<String> params) {
//アニメーションのオブジェクトを非同期に作成
future = AnimationBuilder.with(getQiContext())
.withResources(R.raw.taichichuan_a001).buildAsync()
.andThenCompose(new Function<Animation, Future<Animate>>
() {
@Override
public Future<Animate> execute(Animation animation) throws Throwable
{
//アクションを非同期にビルド
return
AnimateBuilder.with(getQiContext())
.withAnimation(animation).buildAsync();
}
})
.andThenCompose(new Function<Animate, Future<Void>>() {
@Override
public Future<Void> execute(Animate animate) throws Throwable {
Log.i(TAG, "Animation started."
, ConversationItemType.INFO_LOG)
//アクションを非同期に実行
return animate.async().run();
Log.i(TAG, "Animation finished."
, ConversationItemType.INFO_LOG)
}
});
}
@Override
public void stop() {
//アクションをキャンセルする
future.requestCancellation();
Log.i(TAG, "QiChatExecutor stopped");
}
}
このコードでは非同期処理でキャンセルを呼べるようにしていますが、これではいけません。
executorを使ったにもかかわらずrunWith内の処理が非同期のため、runWithを一瞬で抜けてTopicの会話をすぐに再開してしまいます。
では、どうすれば良いのかと言うと…
class MyQiChatExecutor extends BaseQiChatExecutor {
private Future<Void> future = null;
protected MyQiChatExecutor(QiContext context) {
super(context);
}
@Override
public void runWith(List<String> params) {
future = AnimationBuilder.with(getQiContext())
.withResources(R.raw.taichichuan_a001).buildAsync()
.andThenCompose(new Function<Animation
, Future<Animate>>() {
@Override
public Future<Animate> execute(Animation animation) throws Throwable
{
return AnimateBuilder.with(getQiContext())
.withAnimation(animation).buildAsync();
}
})
.andThenCompose(new Function<Animate, Future<Void>>()
{
@Override
public Future<Void> execute(Animate animate) throws Throwable {
Log.i(TAG, "Animation started."
, ConversationItemType.INFO_LOG)
return animate.async().run();
Log.i(TAG, "Animation finished."
, ConversationItemType.INFO_LOG)
}
});
try {
//アニメーションが完了するまで待機
future.get();
//中断されたタスクの結果を受け取る
} catch (ExecutionException e) {
e.printStackTrace();
}
}
@Override
public void stop() {
future.requestCancellation();
Log.i(TAG, "QiChatExecutor stopped");
}
}
これでアニメーションに対して拒否権のあるアプリとなりました❌🩹
上記を参考に、異種への変身1の第一歩を這い出してみてください。🍼🐛
#The Map of QiChatExecutor🌒🔭
^executeを記したTopicファイルを作成してから、QiChatbotを作成しましょう。
Topicファイルにあるexecutorの名前をセットすれば、最終的にChatは非同期に実行されます。
@Override
public void onRobotFocusGained(QiContext qiContext) {
//Topicを作成
final Topic topic = TopicBuilder.with(qiContext)
.withResource(R.raw.execute)
.build();
//QiChatbotを作成
QiChatbot qiChatbot = QiChatbotBuilder.with(qiContext).withTopic(topic).build();
Map<String, QiChatExecutor> executors = new HashMap<>();
//TopicファイルからQiChatExecutorにexecutorの名前をセット
executors.put("myExecutor", new MyQiChatExecutor(qiContext));
//QiChatbotにExecutorをセット
qiChatbot.setExecutors(executors);
//ChatbotBuilderと共にChatをビルド
Chat chat = ChatBuilder.with(qiContext).withChatbot(qiChatbot).build();
//非同期にアクションを実行
chat.async().run();
}
以上を経たサンプルアプリの改造によって、映画のワンシーンのようなやり取りが可能となったPepperがこちらになります🌃👓(※背景はイメージです)
#あとがき
今回もPepperSDKforAndroidを参考に書かせていただきました。
さらに詳しい情報はQiChatExecutorのAPIリファレンスを参照してみてください。
次回はなんと、Basechatbotが登場!🎭💡塩基(base)がDNA上でアデニン(A)・チミン(T)・グアニン(G)・シトシン(C)がスートに変形して合体!?トランプで出来上がったタワーが育ちバベルの塔になる時、天上で見たものは…?3
乞うご期待!🎊🕊