親子でできる!Scratch と AWS を使った “ものづくり” 体験 - 3. AWS の AI サービスを活用して「元気かどうかを判定する」ブロックを完成させよう ! 編

2021-01-05
How to be a Developer

金澤 圭

テクニカルソリューションアーキテクトの金澤 (@ketancho) です。寒い日が続きますね。今年もいろいろな切り口で AWS に関する記事を書いていければと考えています。今年もどうぞよろしくお願いします。

さて、この記事は “親子でできるプログラミング体験 !” 連載の第 3 弾となります。今回で “元気かどうかを判定する” ブロック編が完結となりますので、ぜひ冬休みに親子でものづくりチャレンジをしてみてください !

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. 作業の前提について

今回の記事の前提ですが、これまでの記事で行った作業が完了していることが前提となります。具体的には、
 
  • PC に Git と Node.js がインストールされている必要があります。(親子でひとつ PC があれば問題ありません。)
  • AWS アカウント、および Amazon API Gateway のリソースを作成する権限のある IAM ユーザーが必要です。(もし AWS アカウントをお持ちでない方、IAM ユーザーの作り方が分からない方は、こちらのハンズオン を参考に AWS アカウントと IAM ユーザーを作成してみてください。)
  • 前々回の記事 (環境準備編) と 前回の記事 (クイズ作成を通して if-else を学ぶ編) の作業が終わっていること

こちらの 3 つが前提となります。

前回は、Amazon API Gateway と AWS Lambda を使った独自の Web API を構築し、それを Scratch から呼び出す形を取りました。その際は、Lambda 関数としての実装は文字列が期待する入力になっているかを確認するだけ、というシンプルなものでしたが、今回は Lambda から他の AWS サービスを呼び出すという形を取っていきます。それではやっていきましょう !


2. Web API をアップデートする

さっそく作業を進めていきましょう。今回は、下記のような構成を作っていきます。

AWS には Amazon Comprehend という自然言語処理を行う AI サービスがあります。このサービスには、感情検出する機能があり、今回はこれを使って「元気かどうかを判定する」ブロックを作っていきたいと思います。

2-1. Lambda 関数を作成する

Lambda 関数を作成していくのですが、作成の流れは 前回の記事 と同様になりますので、それを参考にしながら新しく Lambda 関数を作ってみてください。今回は関数名を comprehend-function、ランタイムは前回と同じく Python 3.8 としましょう。ソースコードですが、下記のようになります。

import json
import boto3

comprehend = boto3.client('comprehend')

def lambda_handler(event, context):
    
    input_text = event['queryStringParameters']['input_text']
    
    sentiment_response = comprehend.detect_sentiment(
        Text=input_text,
        LanguageCode='ja'
    )
    sentiment = sentiment_response['Sentiment']
    
    return {
        'statusCode': 200,
        "headers": {
            "Access-Control-Allow-Headers": "Content-Type",
            "Access-Control-Allow-Methods": "GET",
            "Access-Control-Allow-Origin": "*"
        },
        'body': json.dumps({
            "sentiment": sentiment
        })
    }

boto3 (AWS SDK for Python) を利用し、Amazon Comprehend の機能を呼び出している点が前回と違う点になります。boto3 から Amazon Comprehend を利用する方法ですが、こちら の公式ドキュメントを確認しながら実装していく形になります。今回は detect_sentiment メソッドを使いますので、こちら の詳細を確認しながら実装を進め、上のような形になっています。

この記事では、まずは動くものを確認するという意味で、記載のソースコードをそのままコピー & ペーストする形で使ってみてください。その上で、ご自身で機能を拡張する際には、ドキュメントを見ながら各メソッドの仕様を確認し、実装していく形になります。“ドキュメントを読みながら開発する” 実装の流れについては、前回の記事でも紹介した 初学者の方向けのハンズオン で学んでいただけますので、よろしければご覧ください。

さて、この Lamdba 関数はこのままでは 動きません。読み飛ばされてしまうと動かないので太字にしてみました。動かない理由ですが、AWS のサービスを呼び出すには権限が必要です。みなさんが Lambda 関数を作ったり、API Gateway のリソースをできているのは、ログインした IAM ユーザーにその権限が付与されているからです。しかし、Lambda 関数にはその権限がありません。権限を与えるには Lamdba 関数に紐づく IAM ロールに適切なポリシーを与えていきます。

それでは IAM ロールの修正をしていきます。Lambda 関数に紐づく IAM ロールは、Lambda 画面の上部の「アクセス権限」タブから確認することができます。

クリックすると拡大します

実行ロールのリンクがあるので、こちらをクリックしてください。

クリックすると拡大します

IAM ロール画面に遷移するので、こちらの「ポリシーをアタッチします」ボタンをクリックしてください。IAM ロールには複数の IAM ポリシーをアタッチすることができるので、Amazon Comprehend の機能を利用するためのポリシーをアタッチしていきます。(なお、IAM に関するハンズオン も用意しておりますので、あわせてご覧いただければと思います。)

クリックすると拡大します

IAM ポリシーはゼロから作成することもできるのですが、今回は AWS 側であらかじめ用意しているポリシーを使っていきます。検索窓に comprehend と入力した上で、ComprehendReadOnly を選択し「ポリシーのアタッチ」をクリックしてください。

クリックすると拡大します

2-2. API Gateway の設定を変更する

前回の記事で simple-quiz リソースを作成し、GET リクエストを受け付ける形にしました。今回も同じように作業を進めます。同じ流れなので詳細は割愛しますが、

  • リソース名:comprehend
  • メソッドタイプ:GET 
  • Lambda 関数:先程作成したもの (comprehend-function)

を指定し、このような状態になっていることを確認してください。

クリックすると拡大します

前回は使わなかった機能なのですが、API Gateway の機能としてテスト実行ができます。テストを行いたいメソッドを選択し、「テスト」を押してみてください。

クリックすると拡大します

下記のような画面に遷移しますので、左側にクエリ文字列 (ここでは inpute_text = 楽しかったよ としています) を入力し、「テスト」ボタンを押下すると、右側にレスポンスが返ってくることを確認できるかと思います。

クリックすると拡大します

ここまで確認したらデプロイを忘れずに行い (デプロイの流れも前回と同じです)、API Gateway に関する作業も完了です。


3. Scratch 側の修正

もう少しだけ親御さんのパートが続き、「元気かどうかを判定する」独自ブロックの実装を進めていきます。流れとしては、

  • Scratch 上で入力された文字列を引数にして、先程作成した感情を検出する Web API を呼び出す
  • Web API のレスポンス JSON から感情を取り出し、感情が POSITIVE であれば「元気 !」、NEGATIVE であれば「元気がない・・・」、それ以外の場合は「まあまあだよ」という文字列を返す

というブロックを作成します。

前々回、前回と修正を行ったファイル scratch-vm/src/extensions/scratch3_buildersflash/index.js にて独自ブロックとしての挙動を実装していきます。まず、getInfo メソッド内に新規で作るブロックの設定を記述していきます。今回は、blockType を REPORTER とし、値 (文字列) を返すブロックとします。

getInfo () {
        return {
            id: 'buildersflash',
            name: 'New Blocks',
            menuIconURI: menuIconURI,
            blockIconURI: blockIconURI,
            blocks: [
              {
                  opcode: 'callTestAPI',
                  blockType: BlockType.COMMAND,
                  text: 'お父さんのテスト機能を呼び出す'
              },
              {
                  opcode: 'callSimpleQuizAPI',
                  blockType: BlockType.BOOLEAN,
                  text: 'おひるにするあいさつは? [TEXT]',
                  arguments: {
                    TEXT: {
                        type: ArgumentType.STRING,
                        defaultValue: "<ここに入力してね>"
                    }
                }
              },
              // 追加(ここから)
              {
                  opcode: 'getCondition',
                  blockType: BlockType.REPORTER,
                  text: '元気かどうかが分かる特別なブロック [TEXT]',
                  arguments: {
                      TEXT: {
                          type: ArgumentType.STRING,
                          defaultValue: "<ここに入力してね>"
                      }
                  }
              },
              // 追加(ここまで)
            ],
            menus: {
            }
        };
    }

そして、opcode で指定した名前でメソッドを作成し、ブロックの動きを定義していきます。実装の流れとしては、

  • args から入力されたテキスト情報を取り出し、url の末尾にクエリパラメータとして渡し、Web API を呼び出します。url には、先程作成した Web API の URL を入力してください。
  • Web API のレスポンスをデコード後、sentiment の値によってレスポンスを変更します。

となります。

getCondition (args) {
      const text = args.TEXT;
      const ajaxPromise = new Promise(resolve => {
        nets({
          url: "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/comprehend?input_text=" + text
        }, function(err, res, body){
          sentiment = JSON.parse((new TextDecoder).decode(body)).sentiment;
          response = "";
          switch (sentiment) {
            case "POSITIVE":
              response = "元気!";
              break;
            case "NEGATIVE":
              response = "元気がない・・・";
              break;
            default:
              response = "まあまあだよ";
          }
          resolve(response);
        });
      });
      return ajaxPromise;
    }

ここまで実装し、npm start すると「元気かどうかを判定する」ブロックができあがっているはずです。試しに動きを確認してみましょう。「楽しかったよ」と入力しブロックをクリックすると、「元気 !」という文字列が返ってくれば成功です。入力を変更し、「まあまあだよ」や「元気がない・・・」も返ってくることをご確認いただければと思います。

クリックすると拡大します

以上で親パートが完了です🎉 最後に、お子さんとこのブロックを使って元気かを判定する機能を作ってみましょう。


4. 「元気かどうかを判定する」ブロックを使ってみる

「元気かどうかを判定する」ブロックが完成したので、これを使ってプログラミングしていきましょう。今回は、お題を出すので、まずは親子でブロックを組み合わせてそのお題を満たすフローを作ってみてください。最後に回答例をお見せしますので、うまく作れない場合は参考にしていただければと思います。

お題は、

  • 「今日の学校はどうだった ?」と猫が聞く
  • お子さんが答えを入力して、
  • 元気であれば「よかったね !」と返事をする
  • 元気がなければ「そっかー、明日はいい日になるよ !」と返事を出す
  • それ以外のときは「明日も楽しもうね !」と返事をする

です。下のように進むイメージです。ぜひ親子でチャレンジしてみてください !

参考までに、回答例を載せておきます。ご参考にしていただければと思います。

クリックすると拡大します


5. まとめ

親子で「元気かどうかを判定する」ブロックを作成する連載は以上となります🎉

ぜひご感想を頂ければ嬉しいです。(Twitter で #AWSウェブマガジン とつけていただければありがたいです ! )「お父さん(お母さん)すごいじゃん !」と言ってもらえましたでしょうか ? なお、今回の成果物を見た 6 歳の娘からは「猫を前に動かしたりするやつまたやりたい !」というありがたいフィードバックをもらっています。興味を持ってもらえただけで大成功ですよ ! 頑張ってよかったです🙌

また親子でできるものづくりネタを考えて連載できればと思っていますので、またご覧いただければと思います。それでは !


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

金澤 圭 (@ketancho)
アマゾン ウェブ サービス ジャパン合同会社
技術統括本部 ソリューションアーキテクト

サーバーレスが好きなテクニカルソリューションアーキテクト。業種業界問わず、お客様のプロダクト開発をサポートさせていただいています。「AWS Hands-on for Beginners」というオンデマンドで視聴できるハンズオンも企画・推進しており、楽しく学べるコンテンツを日々考えています。好きなサービスは AWS Lambda と AWS Amplify で、好きな休日の過ごし方は娘ふたりと川の字になって昼寝です👧👧

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する