LoginSignup
0
0

More than 3 years have passed since last update.

Pepper SDK入門(27) BaseQiChatExecutorを潤滑油にしてPepperと交流する🎞🌹

Last updated at Posted at 2021-04-19

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)がスートに変形して合体!?トランプで出来上がったタワーが育ちバベルの塔になる時、天上で見たものは…?2
乞うご期待!🎊🕊


  1. フランツ・カフカの『変身』に登場するグレゴール・ザムザ(ヒト)が毒虫になるように、Pepper(機械)が井蛙や窮鼠になる可能性も存在しています。3 

  2. 予告は未来の事象を確約するものではありません。 

  3. 可能性が存在していない可能性も存在しています。 

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0