Vision API を Dialogflow と統合する

1. 始める前に

この Codelab では、Vision API を Dialogflow と統合して、ユーザーが提供した画像入力に対してリッチで動的な機械学習ベースのレスポンスを提供します。画像を入力として受け取り、それを Vision API で処理し、識別したランドマークをユーザーに返す chatbot アプリを作成します。たとえば、ユーザーがタージマハルの画像をアップロードすると、chatbot はレスポンスとしてタージマハルを返します。

これは、画像内の項目を分析し、得られた情報に対してアクションを起こすことができるため、便利です。また、ユーザーが領収書をアップロードし、領収書の購入日を抽出して、妥当な場合は払い戻しを処理できる払い戻し処理システムを構築することもできます。

次のサンプル ダイアログをご覧ください。

ユーザー: こんにちは。

チャットボット: こんにちは。写真をアップロードしてランドマークを探索できます

ユーザー: タージマハルの画像をアップロードしてください。

チャットボット: ファイルを処理しています。検索結果は、タージマハル、タージマハル ガーデン、タージマハルです。

15a4243e453415ca.png

前提条件

先に進む前に、次の Codelab を完了する必要があります。

  1. Dialogflow を使用して予約スケジューラを構築する
  2. Dialogflow chatbot を Actions on Google と統合する
  3. Dialogflow のエンティティについて
  4. Dialogflow アプリ用のフロントエンド Django クライアントを構築する

また、Dialogflow の基本コンセプトと構造も理解する必要があります。これは、「Dialogflow で chatbot を作成する」のコースの次の動画から学ぶことができます。

学習内容

  • Dialogflow エージェントを作成する方法
  • Dialogflow エージェントを更新してファイルをアップロードする方法
  • Dialogflow フルフィルメントとの Vision API 接続を設定する方法
  • Dialogflow 用の Django フロントエンド アプリを設定して実行する方法
  • Django フロントエンド アプリを App Engine の Google Cloud にデプロイする方法
  • カスタム フロントエンドから Dialogflow アプリをテストする方法

作成するアプリの概要

  • Dialogflow エージェントを作成する
  • ファイルをアップロードする Django フロントエンドを実装する
  • Dialogflow フルフィルメントを実装して、アップロードされた画像に対して Vision API を呼び出す

必要なもの

  • Python の基本的な知識
  • Dialogflow の基本知識
  • Vision API の基本知識

2. アーキテクチャの概要

カスタムの Django フロントエンドで新しい会話エクスペリエンスを作成し、Vision API と統合するために拡張します。Django フレームワークでフロントエンドを構築し、ローカルで実行してテストしてから、App Engine にデプロイします。フロントエンドは次のようになります。

5b07e09dc4b84646.png

次の図に示すように、リクエスト フローは次のように機能します。

  1. ユーザーがフロントエンド経由でリクエストを送信します。
  2. これにより、Dialogflow の detectIntent API の呼び出しがトリガーされ、ユーザーの発話が適切なインテントにマッピングされます。
  3. Explore ランドマーク インテントが検出されると、Dialogflow フルフィルメントは Vision API にリクエストを送信してレスポンスを受け取り、ユーザーに送信します。

153725eb50e008d4.png

アーキテクチャ全体は次のようになります。

a2fcea32222a9cb4.png

3. Vision API とは

Vision API は、画像から分析情報を引き出す事前トレーニング済み ML モデルです。画像のラベル付け、顔やランドマークの検出、光学式文字認識、露骨な表現を含むコンテンツのタグ付けなど、複数の分析情報を取得できます。詳細については、Vision AI をご覧ください。

4. Dialogflow エージェントを作成する

  1. Dialogflow コンソールに移動します。
  2. ログインします。(初めて利用する場合は、メールアドレスを使用してご登録ください)。
  3. 利用規約に同意すると、コンソールが表示されます。
  4. [d9e90c93fc779808.png] をクリックし、一番下までスクロールして、[Create new agent] をクリックします。3b3f9677e2a26d93.png
  5. 「VisionAPI」と入力しますエージェント名を入力します。
  6. [作成] をクリックします。

Dialogflow はエージェントの一部として、次の 2 つのデフォルト インテントを作成します。

  1. デフォルトのウェルカム インテントは、ユーザーに挨拶をします。
  2. デフォルトのフォールバック インテントは、bot が理解できない質問をすべて捕捉します。

この時点で、ユーザーに挨拶する機能的な bot ができましたが、画像をアップロードしてランドマークを探索できることをユーザーに示すように更新する必要があります。

デフォルトのウェルカム インテントを更新して、画像をアップロードするようユーザーに通知する

  1. [Default Welcome Intent] をクリックします。
  2. [回答] に移動 >デフォルト >[Text or SSML Response] を選択して、「Hi!写真をアップロードしてランドマークを探索することもできます。

f9cd9ba6917a7aa9.png

エンティティを作成

  1. [エンティティ] をクリックします。

432fff294b666c93.png

  1. [エンティティを作成] をクリックして「filename」という名前を付けます。[保存] をクリックします。

602d001d684485de.png

新しいインテントを作成する

  1. [Intents] >インテントを作成する
  2. 「アップロードした画像を探索」と入力します。Intent name として使用します。
  3. [トレーニング フレーズ] >トレーニング フレーズを追加して、「file is demo.jpg」と入力します。および「ファイルは taj.jpeg@filename をエンティティとして持つユーザー式です。

dd54ebda59c6b896.png

  1. [回答] >回答を追加 >デフォルト >テキストまたは SSML レスポンス。「Assessing file」と入力します[回答を追加] をクリックします。
  2. [Fulfillment] をクリック >フルフィルメントを有効化して、[Enable webhook call for this intent] をオンにします。

b32b7ac054fcc938.png

5. Vision API と統合するフルフィルメントを設定する

  1. [Fulfillment] をクリックします。
  2. [Inline Editor] を有効にします。

c8574c6ef899393f.png

  1. 次のコードで index.js を更新し、YOUR-BUCKET-NAME を実際の Cloud Storage バケットの名前に更新します。
'use strict';

const functions = require('firebase-functions');
const {google} = require('googleapis');
const {WebhookClient} = require('dialogflow-fulfillment');
const vision = require('@google-cloud/vision');
  /**
   * TODO(developer): Uncomment the following lines before running the sample.
   */
const bucketName = 'YOUR-BUCKET-NAME';
const timeZone = 'America/Los_Angeles';
const timeZoneOffset = '-07:00';

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
  const agent = new WebhookClient({ request, response });
  console.log("Parameters", agent.parameters);

  function applyML(agent){
    const filename = agent.parameters.filename;
    console.log("filename is: ", filename);

    // call vision API to detect text
    return callVisionApi(agent, bucketName, filename).then(result => {
                      console.log(`result is ${result}`);
                      agent.add(`file is being processed, here are the results:  ${result}`);
            //agent.add(`file is being processed ${result}`);
        }).catch((error)=> {
            agent.add(`error occurred at apply ml function`  + error);
        });
  }

  let intentMap = new Map();
  intentMap.set('Explore uploaded image', applyML);
  agent.handleRequest(intentMap);
});


async function callVisionApi(agent, bucketName, fileName){
    // [START vision_text_detection_gcs]
  // Imports the Google Cloud client libraries
  // Creates a client
  
  const client = new vision.ImageAnnotatorClient();
    try {
        // Performs text detection on the gcs file
        const [result] = await client.landmarkDetection(`gs://${bucketName}/${fileName}`);
        const detections = result.landmarkAnnotations;
        var detected = [];
        detections.forEach(text => {
            console.log(text.description);
            detected.push(text.description);
        });
        return detected;
    }
    catch(error) {
        console.log('fetch failed', error);
        return [];
    }
}
  1. 次の内容を package.json に貼り付けて内容を置き換えます。
{
  "name": "dialogflowFirebaseFulfillment",
  "description": "Dialogflow fulfillment for the bike shop sample",
  "version": "0.0.1",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": "6"
  },
  "scripts": {
    "lint": "semistandard --fix \"**/*.js\"",
    "start": "firebase deploy --only functions",
    "deploy": "firebase deploy --only functions"
  },
  "dependencies": {
    "firebase-functions": "2.0.2",
    "firebase-admin": "^5.13.1",
    "actions-on-google": "2.2.0", 
    "googleapis": "^27.0.0",
    "dialogflow-fulfillment": "^0.6.1",
    "@google-cloud/bigquery": "^1.3.0",
    "@google-cloud/storage": "^2.0.0",
    "@google-cloud/vision": "^0.25.0"
  }
}
  1. [保存] をクリックします。

6. フロントエンド アプリをダウンロードして実行する

  1. このリポジトリのクローンをローカルマシンに作成します。
https://github.com/priyankavergadia/visionapi-dialogflow.git
  1. コードが含まれているディレクトリに移動します。または、サンプルを zip としてダウンロードして展開することもできます。
cd visionapi-dialogflow

7. ローカル環境を設定する

デプロイすると、アプリは App Engine スタンダード環境に組み込まれている Cloud SQL Proxy を使用して Cloud SQL インスタンスと通信します。ただし、アプリをローカルでテストするには、開発環境に Cloud SQL Proxy のローカルコピーをインストールして使用する必要があります。詳細については、Cloud SQL Proxy についてをご覧ください。

Cloud SQL インスタンスに対して基本的な管理タスクを実行するには、Cloud SQL for MySQL クライアントを使用します。

Cloud SQL Proxy をインストールする

次のコマンドを使用して、Cloud SQL Proxy をダウンロードしてインストールします。Cloud SQL Proxy は、ローカルで実行しているときに Cloud SQL インスタンスに接続するために使用されます。

プロキシをダウンロードします。

curl -o cloud_sql_proxy https://dl.google.com/cloudsql/cloud_sql_proxy.darwin.amd64

プロキシを実行可能にします。

chmod +x cloud_sql_proxy

Cloud SQL インスタンスを作成する

  1. Cloud SQL for MySQL 第 2 世代インスタンスを作成します。「"polls-instance"」などの名前を入力します。インスタンスを使用できるようになるまで数分かかることがあります。準備が整うと、インスタンス リストに表示されます。
  2. 次に、gcloud コマンドライン ツールを使用して、次のコマンドを実行します。ここで、[YOUR_INSTANCE_NAME] は Cloud SQL インスタンスの名前です。次のステップのために、表示された connectionName の値をメモします。[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME] の形式で表示されます。
gcloud sql instances describe [YOUR_INSTANCE_NAME]

または、コンソールでインスタンスをクリックして、インスタンス接続名を取得することもできます。

c11e94464bf4fcf8.png

Cloud SQL インスタンスを初期化する

前のセクションの connectionName を使用して、Cloud SQL Proxy を起動します。

./cloud_sql_proxy -instances="[YOUR_INSTANCE_CONNECTION_NAME]"=tcp:3306

[YOUR_INSTANCE_CONNECTION_NAME] は、前のセクションで記録した値に置き換えます。これにより、ローカルテスト用にローカル コンピュータから Cloud SQL インスタンスへの接続を確立します。アプリをローカルでテストする間、Cloud SQL Proxy を実行したままにします。

次に、新しい Cloud SQL ユーザーとデータベースを作成します。

  1. Google Cloud コンソールを使用して、Cloud SQL インスタンス用の polls-instance という名前の新しいデータベースを作成します。たとえば、「アンケート」と入力し、を使用します。a3707ec9bc38d412.png
  2. Cloud コンソールを使用して、Cloud SQL インスタンスの polls-instance という名前の新しいユーザーを作成します。f4d098fca49cccff.png

データベースの設定を行う

  1. mysite/settings-changeme.py を編集用に開きます。
  2. ファイル名を setting.py に変更します。
  3. 2 つの場所で、[YOUR-USERNAME][YOUR-PASSWORD] を前のセクションで作成したデータベースのユーザー名とパスワードに置き換えます。これは、App Engine のデプロイとローカルテストのためにデータベースへの接続を設定するのに役立ちます。
  4. ‘HOST': ‘cloudsql/ [PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME]'[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME] は、前のセクションで取得したインスタンス名に置き換えます。
  5. 次のコマンドを実行して、出力された connectionName 値をコピーします。これは次のステップで使用します。
gcloud sql instances describe [YOUR_INSTANCE_NAME]
  1. [YOUR-CONNECTION-NAME] は、前のステップで記録した値に置き換えます。
  2. [YOUR-DATABASE] は、前のセクションで選択した名前に置き換えます。
# [START db_setup]
if os.getenv('GAE_APPLICATION', None):
    # Running on production App Engine, so connect to Google Cloud SQL using
    # the unix socket at /cloudsql/<your-cloudsql-connection string>
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '/cloudsql/[PROJECT_NAME]:[REGION_NAME]:[INSTANCE_NAME]',
            'USER': '[YOUR-USERNAME]',
            'PASSWORD': '[YOUR-PASSWORD]',
            'NAME': '[YOUR-DATABASE]',
        }
    }
else:
    # Running locally so connect to either a local MySQL instance or connect to
    # Cloud SQL via the proxy. To start the proxy via command line:
    #     $ cloud_sql_proxy -instances=[INSTANCE_CONNECTION_NAME]=tcp:3306
    # See https://cloud.google.com/sql/docs/mysql-connect-proxy
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'HOST': '127.0.0.1',
            'PORT': '3306',
            'NAME': '[YOUR-DATABASE]',
            'USER': '[YOUR-USERNAME]',
            'PASSWORD': '[YOUR-PASSWORD]'
        }
    }
# [END db_setup]
  1. settings.pyを閉じて保存します。

8. サービス アカウントを設定する

  1. Dialogflow のコンソールで 21a21c1104f5fdf3.png をクリックします。[全般] タブで [Google プロジェクト] に移動します。[プロジェクト ID] をクリックし、[Google Cloud] 7b2236f5627c37a0.png をクリックして Cloud コンソールを開きます。a4cfb880b3c8e789.png
  2. ナビゲーション メニュー 📍? >IAM と管理者 >[サービス アカウント] をクリックし、[Dialogflow の統合] の横にある 796e7c9e65ae751f.png をクリックし、[キーを作成] をクリックします。

3d72abc0c184d281.png

  1. JSON ファイルがパソコンにダウンロードされます。このファイルは、以降の設定セクションで必要になります。

9. アプリから呼び出されるように DialogflowdetectIntent エンドポイントを設定する

  1. チャット フォルダで、key-sample.json を認証情報の JSON ファイルに置き換え、key.json という名前を付けます。
  2. チャット フォルダの views.py で、GOOGLE_PROJECT_ID = "<YOUR_PROJECT_ID>" をプロジェクト ID に変更します。

10. Cloud Storage バケットを作成する

フロントエンドの静的オブジェクト用の Cloud Storage バケットを作成する

  1. Cloud コンソールで、ナビゲーション メニュー Я のナビゲーション アイコンをクリックします。ストレージ

87ff9469db4eb77f.png

  1. [バケットを作成] をクリックします。
  2. グローバルに一意の名前を指定します。

a15a6612e92a39d3.png

  1. データの保存場所の選択[リージョン] を選択して、ニーズに最適なロケーションを選択します。
  2. デフォルトのストレージ クラスとして [Standard] を選択します。

9c56abe632cf61db.png

  1. [バケットレベルで権限を一様に設定する(バケット ポリシーのみ)] を選択し、[続行] をクリックしてバケットを作成します。

f175ac794049df04.png

  1. バケットが作成されたら、ナビゲーション メニュー FetchOptions > をクリックしますストレージ >[参照者] に移動し、作成したバケットを見つけます。

9500ee19b427158c.png

  1. 対応するバケットの横にある 796e7c9e65ae751f.png をクリックし、[バケットの権限を編集] をクリックします。

fd0a310bc3656edd.png

  1. [メンバーを追加] をクリックし、[新しいメンバー] をクリックして「allUsers」と入力し、[ロールを選択] >Storage オブジェクト閲覧者。これにより、allUsers に静的フロントエンド ファイルへの閲覧権限が付与されます。これはファイルにとって理想的なセキュリティ設定ではありませんが、この Codelab の目的には役立ちます。

7519116abd56d5a3.png

ユーザーがアップロードした画像用の Cloud Storage バケットを作成する

同じ手順に沿って、ユーザー画像をアップロードする別のバケットを作成します。権限を「allUsers」に設定するロールとして [Storage オブジェクト作成者] と [Storage オブジェクト閲覧者] を選択します。

11. フロントエンド アプリで Cloud Storage バケットを構成する

settings.py で Cloud Storage バケットを構成する

  1. mysite/setting.py を開きます。
  2. GCS_BUCKET 変数を見つけ、‘<YOUR-GCS-BUCKET-NAME>' と置き換えます。Cloud Storage 静的バケットで無効にできます。
  3. GS_MEDIA_BUCKET_NAME 変数を見つけて、‘<YOUR-GCS-BUCKET-NAME-MEDIA>' と置き換えます。イメージの Cloud Storage バケット名に置き換えます。
  4. GS_STATIC_BUCKET_NAME 変数を見つけて、‘<YOUR-GCS-BUCKET-NAME-STATIC>' と置き換えます。は、静的ファイルの Cloud Storage バケット名に置き換えます。
  5. ファイルを保存します。
GCS_BUCKET = '<YOUR-GCS-BUCKET-NAME>'
GS_MEDIA_BUCKET_NAME = '<YOUR-GCS-BUCKET-NAME-MEDIA>'
GS_STATIC_BUCKET_NAME = '<YOUR-GCS-BUCKET-NAME-STATIC>'

home.html で Cloud Storage バケットを構成する

  • チャット フォルダを開き、templates を開いて、home-changeme.html の名前を home.html に変更します。
  • <YOUR-GCS-BUCKET-NAME-MEDIA> を探し、ユーザーがアップロードしたファイルを保存するバケット名に置き換えます。これにより、ユーザーがアップロードしたファイルをフロントエンドに保存し、静的アセットを Cloud Storage バケット内に保持できなくなります。Vision API は Cloud Storage バケットを呼び出してファイルを取得し、予測を行います。

12. アプリをローカルでビルドして実行する

ローカル コンピュータで Django アプリを実行するには、Python、pip、virtualenv を含む Python 開発環境を設定する必要があります。手順については、Python 開発環境の設定をご覧ください。

  1. 分離された Python 環境を作成し、依存関係をインストールします。
virtualenv env
source env/bin/activate
pip install -r requirements.txt
  1. Django 移行を実行してモデルを設定します。
python3 manage.py makemigrations
python3 manage.py makemigrations polls
python3 manage.py migrate
  1. ローカルのウェブサーバーを起動します。
python3 manage.py runserver
  1. ウェブブラウザで http://localhost:8000/ に移動します。次のようなシンプルなウェブページが表示されます。

8f986b8981f80f7b.png

サンプルアプリのページは、ユーザーのコンピュータ上で実行されている Django ウェブサーバーから提供されます。次に進む準備ができたら、Control+C(Macintosh では Command+C)を押してローカル ウェブサーバーを停止します。

Django 管理コンソールを使用する

  1. スーパーユーザーを作成します。
python3 manage.py createsuperuser
  1. ローカルのウェブサーバーを起動します。
python3 manage.py runserver
  1. ウェブブラウザで http://localhost:8000/admin/ に移動します。管理サイトにログインするために、createsuperuser の実行時に作成したユーザー名とパスワードを入力します。

13. アプリを App Engine スタンダード環境にデプロイする

次のコマンドを実行して、すべての静的コンテンツを 1 つのフォルダに収集します。これにより、アプリのすべての静的ファイルが、settings.pySTATIC_ROOT で指定されたフォルダに移動します。

python3 manage.py collectstatic

app.yaml ファイルが配置されているアプリのディレクトリから次のコマンドを実行して、アプリをアップロードします。

gcloud app deploy

更新が完了したというメッセージが表示されるまで待ちます。

14. フロントエンド アプリをテストする

ウェブブラウザで https://<your_project_id>.appspot.com にアクセスします。

今回は、App Engine スタンダード環境で実行されているウェブサーバーによってリクエストが処理されます。

app deploy コマンドは、app.yaml に記述されているようにアプリをデプロイし、新しくデプロイされたバージョンをデフォルト バージョンとして設定します。これにより、すべての新しいトラフィックが処理されます。

15. 本番環境

製品版でコンテンツを提供する準備ができたら、mysite/settings.pyDEBUG 変数を False に変更します。

16. chatbot をテストする

シミュレータで chatbot をテストするか、以前に構築したウェブまたは Google Home の統合を使用できます。

  1. お客様: 「こんにちは」
  2. chatbot: 「こんにちは。写真をアップロードしてランドマークを探索することもできます。
  3. ユーザーが画像をアップロードします。

この画像をダウンロードして、demo.jpg という名前を付けて使用します。

c3aff843c9f132e4.jpeg

  1. chatbot: 「ファイルが処理中です。結果は次のとおりです: ゴールデン ゲート ブリッジ、ゴールデン ゲート ナショナル レクリエーション エリア、ゴールデン ゲート ブリッジ、ゴールデン ゲート ブリッジ、ゴールデン ゲート ブリッジ。」

全体的には、次のようになります。

228df9993bfc001d.png

17. クリーンアップ

他の Dialogflow Codelab を完了する場合は、このセクションをスキップして、後でここに戻ってください。

Dialogflow エージェントを削除する

  1. 既存のエージェントの横にある ca4337eeb5565bcb.png をクリックします。

520c1c6bb9f46ea6.png

  1. [General] タブで下にスクロールし、[Delete This Agent] をクリックします。
  2. 表示されたウィンドウに「Delete」と入力して、[削除] をクリックします。

18. 完了

Dialogflow で chatbot を作成し、Vision API と統合しました。これで chatbot の開発が可能になりました。

その他の情報

詳細については、Dialogflow の GitHub ページでコードサンプルをご確認ください。