Dialogflow API v1, v2 の webhook リクエスト JSON 例

参考

プロパティの簡単な説明

  • [originalDetectIntentRequest] - [payload] - [surface] - [capabilities]: リクエストを送信してきたデバイスの有効機能
  • [originalDetectIntentRequest] - [payload] - [availableSurfaces] - [capabilities]: リクエストを送信してきたデバイスが連携可能な機能 (スマホへの転送など)

Dialogflow の設定

  • Agent 名: HelloDialogflowAPI2
  • Intent 名: TestIntent1
  • Training phrases:
    • I like green
    • I like red
    • I like blue
  • Parameters:
    • Parameter name: color
    • Entity: @sys.color

呼び出し元

  • Device: Simulator
  • Surface: Phone
  • Language: en-us
  • Location: Googleplex, Mountain View, CA 94043, United States

Webhook リクエスト時に送られる JSON

I like *** をキーボードで入力して呼び出し

v1 API

{
  "originalRequest": {
    "source": "google",
    "version": "2",
    "data": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          }
        ]
      },
      "requestType": "SIMULATOR",
      "inputs": [
        {
          "rawInputs": [
            {
              "query": "I like green",
              "inputType": "KEYBOARD"
            }
          ],
          "arguments": [
            {
              "rawText": "I like green",
              "textValue": "I like green",
              "name": "text"
            }
          ],
          "intent": "actions.intent.TEXT"
        }
      ],
      "user": {
        "lastSeen": "2019-02-11T09:04:57Z",
        "locale": "en-US",
        "userId": "ABwppHGQGr22Z3CnjL-7Hnww_VTTiG9h8n-q9aNsdNlm0OnXPmnX5O8mBi0xJtP5GrhYpQ9gCjJh8khWcmBPuMgnwQ"
      },
      "conversation": {
        "conversationId": "ABwppHH85J9F5oe1VxwSp5TvgkfR-W6DT0Rb_vzAWROIahZIFkKoZHghfajfLrnwSAQqNWYCGVWol7fP1pRRVcVp4A",
        "type": "ACTIVE",
        "conversationToken": "[]"
      },
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            },
            {
              "name": "actions.capability.WEB_BROWSER"
            }
          ]
        }
      ]
    }
  },
  "id": "baa9ed27-e99b-41b0-9d09-35fe3af565ea",
  "timestamp": "2019-02-11T11:26:09.201Z",
  "lang": "en-us",
  "result": {
    "source": "agent",
    "resolvedQuery": "I like green",
    "speech": "",
    "action": "",
    "actionIncomplete": false,
    "parameters": {
      "color": "green"
    },
    "contexts": [
      {
        "name": "actions_capability_screen_output",
        "parameters": {
          "color": "green",
          "color.original": "green"
        },
        "lifespan": 0
      },
      {
        "name": "actions_capability_audio_output",
        "parameters": {
          "color": "green",
          "color.original": "green"
        },
        "lifespan": 0
      },
      {
        "name": "google_assistant_input_type_keyboard",
        "parameters": {
          "color": "green",
          "color.original": "green"
        },
        "lifespan": 0
      },
      {
        "name": "actions_capability_web_browser",
        "parameters": {
          "color": "green",
          "color.original": "green"
        },
        "lifespan": 0
      },
      {
        "name": "actions_capability_media_response_audio",
        "parameters": {
          "color": "green",
          "color.original": "green"
        },
        "lifespan": 0
      }
    ],
    "metadata": {
      "matchedParameters": [
        {
          "dataType": "@sys.color",
          "name": "color",
          "value": "$color",
          "isList": false
        }
      ],
      "isFallbackIntent": "false",
      "intentName": "TestIntent1",
      "isResponseToSlotfilling": false,
      "intentId": "43e7fce7-6325-4087-968d-6a65ed66b34a",
      "webhookUsed": "true",
      "webhookForSlotFillingUsed": "false",
      "nluResponseTime": 23
    },
    "fulfillment": {
      "speech": "",
      "messages": [
        {
          "type": 0,
          "speech": ""
        }
      ]
    },
    "score": 1.0
  },
  "status": {
    "code": 200,
    "errorType": "success"
  },
  "sessionId": "ABwppHH85J9F5oe1VxwSp5TvgkfR-W6DT0Rb_vzAWROIahZIFkKoZHghfajfLrnwSAQqNWYCGVWol7fP1pRRVcVp4A"
}

v2 API

{
  "responseId": "acb3e31d-6d01-47e0-a862-4724a11049af",
  "queryResult": {
    "queryText": "i like blue",
    "parameters": {
      "color": "blue"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            ""
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA/contexts/actions_capability_screen_output",
        "parameters": {
          "color": "blue",
          "color.original": "blue"
        }
      },
      {
        "name": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA/contexts/actions_capability_audio_output",
        "parameters": {
          "color": "blue",
          "color.original": "blue"
        }
      },
      {
        "name": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA/contexts/google_assistant_input_type_keyboard",
        "parameters": {
          "color": "blue",
          "color.original": "blue"
        }
      },
      {
        "name": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA/contexts/actions_capability_media_response_audio",
        "parameters": {
          "color": "blue",
          "color.original": "blue"
        }
      },
      {
        "name": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA/contexts/actions_capability_web_browser",
        "parameters": {
          "color": "blue",
          "color.original": "blue"
        }
      }
    ],
    "intent": {
      "name": "projects/hellodialogflowapi2/agent/intents/43e7fce7-6325-4087-968d-6a65ed66b34a",
      "displayName": "TestIntent1"
    },
    "intentDetectionConfidence": 1.0,
    "languageCode": "en-us"
  },
  "originalDetectIntentRequest": {
    "source": "google",
    "version": "2",
    "payload": {
      "isInSandbox": true,
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.WEB_BROWSER"
          },
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          }
        ]
      },
      "requestType": "SIMULATOR",
      "inputs": [
        {
          "rawInputs": [
            {
              "query": "i like blue",
              "inputType": "KEYBOARD"
            }
          ],
          "arguments": [
            {
              "rawText": "i like blue",
              "textValue": "i like blue",
              "name": "text"
            }
          ],
          "intent": "actions.intent.TEXT"
        }
      ],
      "user": {
        "lastSeen": "2019-02-11T05:33:45Z",
        "locale": "en-US",
        "userId": "ABwppHGQGr22Z3CnjL-7Hnww_VTTiG9h8n-q9aNsdNlm0OnXPmnX5O8mBi0xJtP5GrhYpQ9gCjJh8khWcmBPuMgnwQ"
      },
      "conversation": {
        "conversationId": "ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA",
        "type": "ACTIVE",
        "conversationToken": "[]"
      },
      "availableSurfaces": [
        {
          "capabilities": [
            {
              "name": "actions.capability.WEB_BROWSER"
            },
            {
              "name": "actions.capability.SCREEN_OUTPUT"
            },
            {
              "name": "actions.capability.AUDIO_OUTPUT"
            }
          ]
        }
      ]
    }
  },
  "session": "projects/hellodialogflowapi2/agent/sessions/ABwppHFWb_kxnN18WEBdA9fzj55t2I1kIs88kEAwhj2vY4J0xDAEfw9iU-2t48aI3MSIxVEAIfxNZNt-EJvfUibRfA"
}

Actions on Google で位置情報を毎回使用したい場合

Actions on Google では、ユーザーの位置情報や名前を取得して使用することが出来る。 が、無制限に使用できるわけではなく、情報を得たい場合はユーザーに許可を申請し、ユーザーがその許可を承認して初めて取得できる。 つまり、その為だけにユーザーとのやりとりが一度増えてしまう。

更に、この承認は当該やりとりのみ有効なので、次回のやりとりではまた許可の申請から行う必要がある。 ユーザー名やスマートスピーカーの位置情報の場合は基本的に変わることがないので、毎回承認作業が追加で必要になるのが、お互いに非常にネックとなる。

この問題の対応方法としては、下記

  • 毎回ユーザーに許可申請をする
  • インテント内に位置情報 (位置名) を含めて送ってもらうようにする (送ってもらった名称から必要な位置情報にサーバー側で変換できる必要がある)
  • 最初に取得した位置情報を userId に紐づけて保存しておき、次回以降は保存しておいた情報を使用する

参考

UWP アプリ開発メモ

証明書の有効期間が切れて申請用パッケージの作成に失敗する時の、更新方法

  1. VS で当該プロジェクトを開く
  2. [ソリューション エクスプローラー] で当該プロジェクトを右クリックし、プロパティを表示する
  3. [アプリケーション] タブを選択し、[パッケージ マニフェスト] ボタンをクリックする
  4. [パッケージ化] タブをクリックし、[発行者] テキストボックスに表示されている文字列をコピーしておく(後で使用する)
  5. [証明書の選択...] ボタンをクリックする
  6. [証明書の構成] ボタンをクリックし、[テスト証明書の作成...] ボタンをクリックする
  7. [発行者共通名] テキストボックスに、コピーしておいた [発行者] の文字列のうち「CN=」から後ろの文字列を貼り付け、[OK] ボタンをクリックする
  8. 有効期限が更新されていることを確認して、[OK] ボタンをクリックする

補足: 公開中アプリの [発行者共通名] については、Partner Center ダッシュボードで当該アプリを選択し、[App Management] - [App identity] - [Package/Identity/Publisher] の値でも確認できる

「'ValidateAppxPackage' に失敗しました。ファイル '...\Package.StoreAssociation.xml' が見つかりませんでした。」エラーが表示される場合の対処方法

  1. VS で当該プロジェクトを開く
  2. [ソリューション エクスプローラー] で当該プロジェクトを右クリックし、プロパティを表示する
  3. [アプリケーション] タブを選択し、[パッケージ マニフェスト] ボタンをクリックする
  4. [パッケージ化] タブをクリックし、[パッケージ名] テキストボックスに表示されている文字列を控えておく(この画面を表示したまま以降の作業実施でも可)
  5. [ソリューション エクスプローラー] で当該プロジェクトを右クリックし、[ストア] - [アプリケーションをストアと関連付ける] をクリックする
  6. [アプリケーション名を選択] 画面で、[既にパッケージに使用されているアプリケーション名を含める] チェックボックスにチェックを入れ、[既存のアプリケーション名] リストから目的のアプリを選択する。[Windows ストア内のパッケージ ID] 情報が、事前に確認していた [パッケージ名] の ID と合っているか、確認しておく
  7. 本当にこのアプリで合っているかなどの確認が表示されるので、問題なければ [次へ] ボタンをクリックする
  8. [関連付け] ボタンをクリックして、関連付けを行う。"Package.StoreAssociation.xml" ファイルが生成される

Release ビルドでの実行時に System.Reflection.MissingMetadataException が発生する場合の対処方法

Debug ビルドでは問題ないが、Release ビルドで実行した際に以下のようなエラーが発生する場合がある。

System.Reflection.MissingMetadataException
  HResult=0x80131543
  Message=Reflection_InsufficientMetadata_NoHelpAvailable: EETypeRva:0x00022f50. For more information, visit http://go.microsoft.com/fwlink/?LinkId=623485

JsonConvert を使ったリフレクションなどが行われる箇所で発生している可能性があるかも。 この場合、xxx.rd.xml と言う名前のファイルをプロジェクトに追加する必要がある。

ただ、xxx.rd.xml ファイルには発生しているエラーに沿った内容を記述する必要があり、これが結構困難。ここでは自分が解決できた方法を例として載せるが、本当にこれで適切に記述できているかは正直不明。

  1. Release ビルドでは例外がスローされても具体的に何を処理しようとしてエラーとなったかが不明なので、Debug ビルドで例外を起こす必要がある。ただしこのエラーは Release ビルド特有の最適化が影響しており、Debug ビルドでは既定で無効になっているので、これを有効にした上で Debug 実行を行い、例外の詳細を確認する必要がある。
    アプリのプロジェクトのプロパティを表示し、[ビルド] - [.NET ネイティブ ツール チェーンでコンパイルする] チェックボックスにチェックを付けてからビルドする

  2. 今度は例外スロー時に、以下のようにもう少し詳細な情報が出力される

  System.Reflection.MissingMetadataException
    HResult=0x80131543
    Message='Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder' is missing metadata. For more 
  information, please visit http://go.microsoft.com/fwlink/?LinkID=392859

上記の Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder が問題を解決すべき対象となる。

  1. 上記のように missing metadata とか出たら、完全に xxx.rd.xml が必要なパターンなので、以下の処理を行う
  2. アプリのプロジェクトに xxx.rd.xml みたいなファイルが含まれない場合は、プロジェクトにファイルを追加する。名前は default.rd.xml とかにする。また、ファイルのビルドアクションは "コンテンツ" とする
  3. default.rd.xml の内容を以下のようにする
<?xml version="1.0" encoding="utf-8"?>
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <!--<Type Name="Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder" Dynamic="Required All" />-->
    <Namespace Name="Microsoft.CSharp.RuntimeBinder" Dynamic="Required All" />
  </Application>
</Directives>

上記では初め Type 指定で Microsoft.CSharp.RuntimeBinder.CSharpGetMemberBinder を指定したのだが、Microsoft.CSharp.RuntimeBinder 名前空間の別の型でまた同じ例外が起きてしまったので、型レベルではなく、名前空間で指定している。自分の場合は上記内容で本例外を回避することが出来た。

ソルデフ データ

自分で確認した情報をスプレッドシートにまとめているので、それを公開。 今の所、下記情報を記載。

  • 通常マップ (3-2 まで)
    • ルーン

行ヘッダでフィルタ設定して公開したつもりなんですが、閲覧者として使おうとするとうまくフィルタされないので、フィルタ等についてはご自身で行ってください。

何かありましたら、ツイッターやっていますのでお気軽にご連絡ください。(@poke_dev)

docs.google.com

.NET で文字列の暗号化を行う

非対称アルゴリズム(ハッシュ化)

System.Web.Helpers.Crypt.HashPassword() が使える(他のも色々あるっぽいけど)。 ハッシュ化された文字列には使用された salt も含まれるので、使う側は salt の保存などは考慮する必要なく、また、同一文字列をハッシュ化しても別文字列を得ることが出来る。

Password management made easy in ASP.NET with the Crypto API | brockallen

対照アルゴリズム

種類はいくつかあるようだが、実質的に AesManaged クラス一択の様子。

暗号化に使用する IV については分かっても問題ないらしいので、毎回生成して、暗号化後の文字列の先頭に追加する形式をとった方が良い。 毎回生成することで、仮に同じ文字列を暗号化したとしても得られる暗号化済みの文字列は異なる文字列になる。 復号化の際は、先頭に IV が追加されていることを前提に処理する必要がある。

Key についてはどこか安全な場所に保存して使用する必要がある。Azure であればアプリ設定で良いと思うが、更に厳重に管理する必要があるなら Key Vault とかになるのではないかと思う。

BlockSize, Mode, Padding などのオプションは、既定の設定で問題ないっぽい。

AesManaged Class (System.Security.Cryptography) | Microsoft Docs

ASP.NET MVC の認証周りについて

ASP.NET のセッションは Session Fixation 問題を抱えるため、認証には認証用に用意されている Form 認証を使用する。

MVC で認証ありサイトを作る時は、RegisterGlobalFilters() で AuthorizeAttribute を Filter に追加して、基本的にサイト全体で認証必要な状態にした方がたぶん安全。 認証不要なページ(コントローラー)は、明示的に AllowAnonymous 属性を付加して対応する。

(Form 認証ではなく)セッションが有効な状態かは、コントローラーの OnAuthorization() でチェックする。ベースコントローラーレベルでチェックするのを推奨。 なお、このイベントでリダイレクトする時は、Response.Redirect() ではなく、filterContext.Result にセットすることで行う必要がある。