サーフェス機能(Dialogflow)

Dialogflow で探索

[続行] をクリックして、Dialogflow に Surface 機能のサンプルをインポートします。次に、 サンプルをデプロイしてテストする手順は次のとおりです。

  1. エージェント名を入力し、サンプルの新しい Dialogflow エージェントを作成します。
  2. エージェントのインポートが完了したら、[Go to agent] をクリックします。
  3. メインのナビゲーション メニューから [Fulfillment] に移動します。
  4. [Inline Editor] を有効にして、[Deploy] をクリックします。エディタにはサンプルが含まれています。 できます。
  5. メイン ナビゲーション メニューから [Integrations] に移動し、[Google] をクリックします アシスタント
  6. 表示されたモーダル ウィンドウで、[変更の自動プレビュー] を有効にして [テスト] をクリックします。 Actions シミュレータを開きます
  7. シミュレータで「Talk to my test app」と入力して、サンプルをテストします。
<ph type="x-smartling-placeholder"></ph> 続行

アクションは、音声のみを含むさまざまなサーフェスで表示できます。 サーフェス(スマート スピーカー)と、ディスプレイサーフェス(スマートディスプレイや あります。

あらゆるサーフェスで適切に機能する会話を設計して構築するには、Surface を使用します 会話を適切に制御し、その範囲を限定できます。

アクションのサーフェス機能

Actions on Google では、ユーザーのアクションに基づいて、ユーザーがアクションを呼び出せるかどうかを 表示されなくなります。サポートされていないサーフェスでユーザーがアクションを呼び出そうとすると、使用中のデバイスがサポートされていないことを知らせるエラー メッセージが発生します。

アクションでどのサーフェスをサポートするかは、Actions プロジェクトで定義します。

アクションはさまざまなサーフェスに表示できる スマートフォン(Android、iOS)や Google Home デバイス。

ランタイム サーフェス機能

ランタイム サーフェス機能でユーザー エクスペリエンスを提供する方法には、主に次の 2 通りがあります。

  • 回答の分岐 - 異なる回答をユーザーに提示しますが、 同じ構造とフローで会話を進めることができます。対象 たとえば天気のアクションでは、スマートフォンに表示された画像付きのカードが表示され、 音声ファイルを Google Home で再生しますが、会話の流れは同じです。 表示されなくなります。
  • 会話の分岐 - サーフェスごとにまったく異なる会話をユーザーに提示します。たとえば、料理注文アプリを作成する場合、Google Home では再注文フローを提供するのに対して、スマートフォンでは完全なカート アセンブリのフローを提供できます。会話を分岐させるには、Dialogflow コンテキストを使用して、Dialogflow でインテントをトリガーする対象範囲を特定のサーフェス機能に限定します。実際の Dialogflow インテントは、特定のリクエストが サーフェスの能力が満たされているかどうかを表します。

  • マルチサーフェス会話 - あるサーフェスでユーザーと会話を始め、会話の途中で別のサーフェスに移行します。たとえば ユーザーが Google 検索などの音声のみのサーフェスで画像を含むアクションを呼び出したとき ビジュアル スペースで別のサーフェスを探すためのアクションを作成できます。 可能であれば会話をその機能に移します

レスポンスの分岐

フルフィルメントが Google アシスタントからリクエストを受け取るたびに、次のサーフェス(たとえば、Google Home や Android スマートフォン)の機能を問い合わせることができます。

const hasScreen =
  conv
.surface.capabilities.has('actions.capability.SCREEN_OUTPUT');
 
// OR conv.screen;
const hasAudio =
  conv
.surface.capabilities.has('actions.capability.AUDIO_OUTPUT');
const hasMediaPlayback =
  conv
.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO');
const hasWebBrowser =
  conv
.surface.capabilities.has('actions.capability.WEB_BROWSER');
// Interactive Canvas must be enabled in your project to see this
const hasInteractiveCanvas =
  conv
.surface.capabilities.has('actions.capability.INTERACTIVE_CANVAS');
boolean hasScreen = request.hasCapability(Capability.SCREEN_OUTPUT.getValue());
boolean hasAudio = request.hasCapability(Capability.AUDIO_OUTPUT.getValue());
boolean hasMediaPlayback = request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue());
boolean hasWebBrowser = request.hasCapability(Capability.WEB_BROWSER.getValue());
// Interactive Canvas must be enabled in your project to see this
boolean hasInteractiveCanvas = request.hasCapability("INTERACTIVE_CANVAS");
const hasScreen =
  conv
.surface.capabilities.has('actions.capability.SCREEN_OUTPUT');
 
// OR conv.screen;
const hasAudio =
  conv
.surface.capabilities.has('actions.capability.AUDIO_OUTPUT');
const hasMediaPlayback =
  conv
.surface.capabilities.has('actions.capability.MEDIA_RESPONSE_AUDIO');
const hasWebBrowser =
  conv
.surface.capabilities.has('actions.capability.WEB_BROWSER');
// Interactive Canvas must be enabled in your project to see this
const hasInteractiveCanvas =
  conv
.surface.capabilities.has('actions.capability.INTERACTIVE_CANVAS');
boolean hasScreen = request.hasCapability(Capability.SCREEN_OUTPUT.getValue());
boolean hasAudio = request.hasCapability(Capability.AUDIO_OUTPUT.getValue());
boolean hasMediaPlayback = request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue());
boolean hasWebBrowser = request.hasCapability(Capability.WEB_BROWSER.getValue());
// Interactive Canvas must be enabled in your project to see this
boolean hasInteractiveCanvas = request.hasCapability("INTERACTIVE_CANVAS");

下記の JSON は Webhook リクエストを示します。

{
 
"responseId": "206a66fb-a572-4cfc-9e41-8e2eb62fdf18-712767ed",
 
"queryResult": {
   
"queryText": "Current capabilities",
   
"parameters": {},
   
"allRequiredParamsPresent": true,
   
"fulfillmentText": "Webhook failed for intent: Current Capabilities",
   
"fulfillmentMessages": [
     
{
       
"text": {
         
"text": [
           
"Webhook failed for intent: Current Capabilities"
         
]
       
}
     
}
   
],
   
"outputContexts": [
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_media_response_audio"
     
},
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_audio_output"
     
},
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_account_linking"
     
},
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_web_browser"
     
},
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_screen_output"
     
},
     
{
       
"name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/google_assistant_input_type_touch"
     
}
   
],
   
"intent": {
     
"name": "projects/df-surface-caps-kohler/agent/intents/4e191eef-ba17-4f68-8a97-85a43cbc9ed1",
     
"displayName": "Current Capabilities"
   
},
   
"intentDetectionConfidence": 1,
   
"languageCode": "en"
 
},
 
"originalDetectIntentRequest": {
   
"source": "google",
   
"version": "2",
   
"payload": {
     
"user": {
       
"locale": "en-US",
       
"userVerificationStatus": "VERIFIED"
     
},
     
"conversation": {
       
"conversationId": "ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ",
       
"type": "ACTIVE",
       
"conversationToken": "[]"
     
},
     
"inputs": [
       
{
         
"intent": "actions.intent.TEXT",
         
"rawInputs": [
           
{
             
"inputType": "TOUCH",
             
"query": "Current capabilities"
           
}
         
],
         
"arguments": [
           
{
             
"name": "text",
             
"rawText": "Current capabilities",
             
"textValue": "Current capabilities"
           
}
         
]
       
}
     
],
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          },
          {
            "name": "actions.capability.ACCOUNT_LINKING"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          },
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          }
        ]
      },
     
"availableSurfaces": [
       
{
         
"capabilities": [
           
{
             
"name": "actions.capability.AUDIO_OUTPUT"
           
},
           
{
             
"name": "actions.capability.SCREEN_OUTPUT"
           
},
           
{
             
"name": "actions.capability.WEB_BROWSER"
           
}
         
]
       
}
     
]
   
}
 
},
 
"session": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ"
}

下記の JSON は Webhook リクエストを示します。

{
 
"user": {
   
"locale": "en-US",
   
"userVerificationStatus": "VERIFIED"
 
},
 
"conversation": {
   
"conversationId": "ABwppHENuB8dw7LgVquXnW5Bmy9hwu1Qz4bsaL7uIb9vDSBYPAFhFgsMWnMV6m4JEDgaUWz9FUVuIhQqWh1KZ_jjTwKEIlza",
   
"type": "NEW"
 
},
 
"inputs": [
   
{
     
"intent": "actions.intent.TEXT",
     
"rawInputs": [
       
{
         
"inputType": "TOUCH",
         
"query": "Current capabilities"
       
}
     
],
     
"arguments": [
       
{
         
"name": "text",
         
"rawText": "Current capabilities",
         
"textValue": "Current capabilities"
       
}
     
]
   
}
 
],
  "surface": {
    "capabilities": [
      {
        "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
      },
      {
        "name": "actions.capability.SCREEN_OUTPUT"
      },
      {
        "name": "actions.capability.WEB_BROWSER"
      },
      {
        "name": "actions.capability.ACCOUNT_LINKING"
      },
      {
        "name": "actions.capability.AUDIO_OUTPUT"
      }
    ]
  },
 
"availableSurfaces": [
   
{
     
"capabilities": [
       
{
         
"name": "actions.capability.WEB_BROWSER"
       
},
       
{
         
"name": "actions.capability.AUDIO_OUTPUT"
       
},
       
{
         
"name": "actions.capability.SCREEN_OUTPUT"
       
}
     
]
   
}
 
]
}

会話の分岐

事前定義された Dialogflow コンテキストを使用して、Dialogflow インテントを特定のサーフェスでのみトリガーするように設定できます。インテントが一致するたびに、Dialogflow は デバイスがサーフェス機能のセットからコンテキストを自動生成 見ていきますこれらのコンテキストの 1 つ以上を「入力コンテキスト」として指定できます 渡します。これにより、インテントのトリガーをモダリティに基づいて制御できます。

たとえば、画面出力のあるデバイスでのみインテントをトリガーしたい場合は、 インテントの入力コンテキストを actions_capability_screen_output に設定できます。

次のコンテキストが用意されています。

  • actions_capability_audio_output - デバイスにはスピーカーが搭載されています。
  • actions_capability_screen_output - デバイスには出力ディスプレイ画面があります。
  • actions_capability_media_response_audio - デバイスはメディア コンテンツの再生をサポートします。
  • actions_capability_web_browser - デバイスはウェブブラウザをサポートしています。(この機能は現在、スマートディスプレイでは使用できません)。

画面を持つサーフェスでのみトリガーされるインテントの例を次に示します。

マルチサーフェス会話

アクションのフローのどの時点でも、ユーザーが特定の機能を備えた他のサーフェスを持っているかどうかを確認できます。リクエストされた機能を持つ別のサーフェスが使用可能な場合は、現在の会話をその新しいサーフェスに転送できます。

サーフェス転送のフローは次のとおりです。

  1. ユーザーに利用可能なサーフェスがあるかどうかを確認する

    Webhook ハンドラで、ユーザーが特定の機能を備えたサーフェスを持っているかどうかを問い合わせることができます。このサーフェスは 1 つのタイルに ソースサーフェスと同じ Google アカウントを使用する必要があります。

    const screenAvailable =
      conv
    .available.surfaces.capabilities.has(
       
    'actions.capability.SCREEN_OUTPUT');
    String screen = Capability.SCREEN_OUTPUT.getValue();
    boolean screenAvailable = false;
    for (Surface surface : request.getAvailableSurfaces()) {
     
    for (com.google.api.services.actions_fulfillment.v2.model.Capability capability :
          surface
    .getCapabilities()) {
       
    if (capability.getName().equals(screen)) {
          screenAvailable
    = true;
         
    break;
       
    }
     
    }
    }
    const screenAvailable =
      conv
    .available.surfaces.capabilities.has(
       
    'actions.capability.SCREEN_OUTPUT');
    String screen = Capability.SCREEN_OUTPUT.getValue();
    boolean screenAvailable = false;
    for (Surface surface : request.getAvailableSurfaces()) {
     
    for (com.google.api.services.actions_fulfillment.v2.model.Capability capability :
          surface
    .getCapabilities()) {
       
    if (capability.getName().equals(screen)) {
          screenAvailable
    = true;
         
    break;
       
    }
     
    }
    }

    下記の JSON は Webhook リクエストを示します。

    {
     
    "responseId": "206a66fb-a572-4cfc-9e41-8e2eb62fdf18-712767ed",
     
    "queryResult": {
       
    "queryText": "Current capabilities",
       
    "parameters": {},
       
    "allRequiredParamsPresent": true,
       
    "fulfillmentText": "Webhook failed for intent: Current Capabilities",
       
    "fulfillmentMessages": [
         
    {
           
    "text": {
             
    "text": [
               
    "Webhook failed for intent: Current Capabilities"
             
    ]
           
    }
         
    }
       
    ],
       
    "outputContexts": [
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_media_response_audio"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_audio_output"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_account_linking"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_web_browser"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/actions_capability_screen_output"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ/contexts/google_assistant_input_type_touch"
         
    }
       
    ],
       
    "intent": {
         
    "name": "projects/df-surface-caps-kohler/agent/intents/4e191eef-ba17-4f68-8a97-85a43cbc9ed1",
         
    "displayName": "Current Capabilities"
       
    },
       
    "intentDetectionConfidence": 1,
       
    "languageCode": "en"
     
    },
     
    "originalDetectIntentRequest": {
       
    "source": "google",
       
    "version": "2",
       
    "payload": {
         
    "user": {
           
    "locale": "en-US",
           
    "userVerificationStatus": "VERIFIED"
         
    },
         
    "conversation": {
           
    "conversationId": "ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ",
           
    "type": "ACTIVE",
           
    "conversationToken": "[]"
         
    },
         
    "inputs": [
           
    {
             
    "intent": "actions.intent.TEXT",
             
    "rawInputs": [
               
    {
                 
    "inputType": "TOUCH",
                 
    "query": "Current capabilities"
               
    }
             
    ],
             
    "arguments": [
               
    {
                 
    "name": "text",
                 
    "rawText": "Current capabilities",
                 
    "textValue": "Current capabilities"
               
    }
             
    ]
           
    }
         
    ],
          "surface": {
            "capabilities": [
              {
                "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
              },
              {
                "name": "actions.capability.AUDIO_OUTPUT"
              },
              {
                "name": "actions.capability.ACCOUNT_LINKING"
              },
              {
                "name": "actions.capability.WEB_BROWSER"
              },
              {
                "name": "actions.capability.SCREEN_OUTPUT"
              }
            ]
          },
         
    "availableSurfaces": [
           
    {
             
    "capabilities": [
               
    {
                 
    "name": "actions.capability.AUDIO_OUTPUT"
               
    },
               
    {
                 
    "name": "actions.capability.SCREEN_OUTPUT"
               
    },
               
    {
                 
    "name": "actions.capability.WEB_BROWSER"
               
    }
             
    ]
           
    }
         
    ]
       
    }
     
    },
     
    "session": "projects/df-surface-caps-kohler/agent/sessions/ABwppHG7pYytu-kJGJApvrFTk2iNkshy-NLsjlzJg2ntVbxZkoz-rdFch3Fd8Vmlgf0VxmNSK1woelx1otayGwCnE8gzAQ"
    }

    下記の JSON は Webhook リクエストを示します。

    {
     
    "user": {
       
    "locale": "en-US",
       
    "userVerificationStatus": "VERIFIED"
     
    },
     
    "conversation": {
       
    "conversationId": "ABwppHENuB8dw7LgVquXnW5Bmy9hwu1Qz4bsaL7uIb9vDSBYPAFhFgsMWnMV6m4JEDgaUWz9FUVuIhQqWh1KZ_jjTwKEIlza",
       
    "type": "NEW"
     
    },
     
    "inputs": [
       
    {
         
    "intent": "actions.intent.TEXT",
         
    "rawInputs": [
           
    {
             
    "inputType": "TOUCH",
             
    "query": "Current capabilities"
           
    }
         
    ],
         
    "arguments": [
           
    {
             
    "name": "text",
             
    "rawText": "Current capabilities",
             
    "textValue": "Current capabilities"
           
    }
         
    ]
       
    }
     
    ],
      "surface": {
        "capabilities": [
          {
            "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
          },
          {
            "name": "actions.capability.SCREEN_OUTPUT"
          },
          {
            "name": "actions.capability.WEB_BROWSER"
          },
          {
            "name": "actions.capability.ACCOUNT_LINKING"
          },
          {
            "name": "actions.capability.AUDIO_OUTPUT"
          }
        ]
      },
     
    "availableSurfaces": [
       
    {
         
    "capabilities": [
           
    {
             
    "name": "actions.capability.WEB_BROWSER"
           
    },
           
    {
             
    "name": "actions.capability.AUDIO_OUTPUT"
           
    },
           
    {
             
    "name": "actions.capability.SCREEN_OUTPUT"
           
    }
         
    ]
       
    }
     
    ]
    }
  2. ユーザーを新しいサーフェスに転送するリクエスト

    必要な機能を持つサーフェスが使用可能な場合は、会話を転送するかどうかをユーザーに確認します。

    if (conv.screen) {
      conv
    .ask(`You're already on a screen device.`);
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Current Capabilities',
       
    'Check Audio Capability',
       
    'Check Screen Capability',
       
    'Check Media Capability',
       
    'Check Web Capability',
     
    ]));
     
    return;
    } else if (screenAvailable) {
     
    const context =
       
    `Let's move you to a screen device for cards and other visual responses`;
     
    const notification = 'Try your Action here!';
     
    const capabilities = ['actions.capability.SCREEN_OUTPUT'];
     
    return conv.ask(new NewSurface({context, notification, capabilities}));
    } else {
      conv
    .ask('It looks like there is no screen device ' +
       
    'associated with this user.');
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Current Capabilities',
       
    'Check Audio Capability',
       
    'Check Screen Capability',
       
    'Check Media Capability',
       
    'Check Web Capability',
     
    ]));
    };
    ResponseBuilder responseBuilder = getResponseBuilder(request);
    if (request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) {
      responseBuilder
    .add("You're already on a screen device");
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Transfer surface",
           
    "Check Audio Capability",
           
    "Check Screen Capability",
           
    "Check Media Capability",
           
    "Check Web Capability",
         
    });
     
    return responseBuilder.build();
    } else if (screenAvailable) {
      responseBuilder
    .add(
         
    new NewSurface()
             
    .setContext("Let's move you to a screen device for cards and other visual responses")
             
    .setNotificationTitle("Try your Action here!")
             
    .setCapabilities(Collections.singletonList(screen)));
     
    return responseBuilder.build();
    } else {
      responseBuilder
    .add("It looks like there is no screen device associated with this user.");
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Transfer surface",
           
    "Check Audio Capability",
           
    "Check Screen Capability",
           
    "Check Media Capability",
           
    "Check Web Capability",
         
    });
     
    return responseBuilder.build();
    }
    if (conv.screen) {
      conv
    .ask(`You're already on a screen device.`);
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Transfer surface',
       
    'Current capabilities',
     
    ]));
     
    return;
    } else if (screenAvailable) {
     
    const context =
       
    `Let's move you to a screen device for cards and other visual responses`;
     
    const notification = 'Try your Action here!';
     
    const capabilities = ['actions.capability.SCREEN_OUTPUT'];
     
    return conv.ask(new NewSurface({context, notification, capabilities}));
    } else {
      conv
    .ask('It looks like there is no screen device ' +
       
    'associated with this user.');
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Transfer surface',
       
    'Current capabilities',
     
    ]));
    };
    ResponseBuilder responseBuilder = getResponseBuilder(request);
    if (request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) {
      responseBuilder
    .add("You're already on a screen device");
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Current capabilities", "Transfer surface",
         
    });
     
    return responseBuilder.build();
    } else if (screenAvailable) {
      responseBuilder
    .add(
         
    new NewSurface()
             
    .setContext("Let's move you to a screen device for cards and other visual responses")
             
    .setNotificationTitle("Try your Action here!")
             
    .setCapabilities(Collections.singletonList(screen)));
     
    return responseBuilder.build();
    } else {
      responseBuilder
    .add("It looks like there is no screen device associated with this user.");
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Current capabilities", "Transfer surface",
         
    });
     
    return responseBuilder.build();
    }

    下記の JSON は Webhook レスポンスを示します。

    {
     
    "payload": {
       
    "google": {
         
    "expectUserResponse": true,
         
    "systemIntent": {
           
    "intent": "actions.intent.NEW_SURFACE",
           
    "data": {
             
    "@type": "type.googleapis.com/google.actions.v2.NewSurfaceValueSpec",
             
    "capabilities": [
               
    "actions.capability.SCREEN_OUTPUT"
             
    ],
             
    "context": "Let's move you to a screen device for cards and other visual responses",
             
    "notificationTitle": "Try your Action here!"
           
    }
         
    }
       
    }
     
    }
    }

    下記の JSON は Webhook レスポンスを示します。

    {
     
    "expectUserResponse": true,
     
    "expectedInputs": [
       
    {
         
    "possibleIntents": [
           
    {
             
    "intent": "actions.intent.NEW_SURFACE",
             
    "inputValueData": {
               
    "@type": "type.googleapis.com/google.actions.v2.NewSurfaceValueSpec",
               
    "capabilities": [
                 
    "actions.capability.SCREEN_OUTPUT"
               
    ],
               
    "context": "Let's move you to a screen device for cards and other visual responses",
               
    "notificationTitle": "Try your Action here!"
             
    }
           
    }
         
    ]
       
    }
     
    ]
    }
  3. お客様の応答を処理する

    リクエストに対するユーザーのレスポンスに基づいて、アクションは 元のサーフェスに会話の引き継ぎや制御を戻すことができます。 いずれの場合も、エンドポイントへの次のリクエストには actions.intent.NEW_SURFACE が含まれます。 そのイベントでトリガーされるインテントを 対応するハンドラを作成します。このハンドラコードでは、転送が成功したかどうかを確認する必要があります。

    app.intent('Transfer Surface - NEW_SURFACE', (conv, input, newSurface) => {
     
    if (newSurface.status === 'OK') {
        conv
    .ask('Welcome to a screen device!');
        conv
    .ask(new BasicCard({
          title
    : `You're on a screen device!`,
          text
    : `Screen devices support basic cards and other visual responses!`,
       
    }));
     
    } else {
        conv
    .ask(`Ok, no problem.`);
     
    }
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Current Capabilities',
       
    'Check Audio Capability',
       
    'Check Screen Capability',
       
    'Check Media Capability',
       
    'Check Web Capability',
     
    ]));
    });
    @ForIntent("Transfer Surface - NEW_SURFACE")
    public ActionResponse newSurface(ActionRequest request) {
     
    ResponseBuilder responseBuilder = getResponseBuilder(request);
     
    Map<String, Object> newSurfaceStatus = request.getArgument("NEW_SURFACE").getExtension();
     
    if (newSurfaceStatus.get("status").equals("OK")) {
        responseBuilder
    .add("Welcome to a screen device!");
        responseBuilder
    .add(
           
    new BasicCard()
               
    .setTitle("You're on a screened device!")
               
    .setFormattedText("Screen devices support basic cards and other visual responses!"));
     
    } else {
        responseBuilder
    .add("Ok, no problem.");
     
    }
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Transfer surface",
           
    "Check Audio Capability",
           
    "Check Screen Capability",
           
    "Check Media Capability",
           
    "Check Web Capability",
         
    });
     
    return responseBuilder.build();
    }
    app.intent('actions.intent.NEW_SURFACE', (conv) => {
     
    if (conv.arguments.get('NEW_SURFACE').status === 'OK') {
        conv
    .ask('Welcome to a screen device!');
        conv
    .ask(new BasicCard({
          title
    : `You're on a screen device!`,
          text
    : `Screen devices support basic cards and other visual responses!`,
       
    }));
     
    } else {
        conv
    .ask(`Ok, no problem.`);
     
    }
      conv
    .ask('What else would you like to try?');
      conv
    .ask(new Suggestions([
       
    'Transfer surface',
       
    'Current capabilities',
     
    ]));
    });
    @ForIntent("actions.intent.NEW_SURFACE")
    public ActionResponse newSurface(ActionRequest request) {
     
    ResponseBuilder responseBuilder = getResponseBuilder(request);
     
    Map<String, Object> newSurfaceStatus = request.getArgument("NEW_SURFACE").getExtension();
     
    if (newSurfaceStatus.get("status").equals("OK")) {
        responseBuilder
    .add("Welcome to a screen device!");
        responseBuilder
    .add(
           
    new BasicCard()
               
    .setTitle("You're on a screened device!")
               
    .setFormattedText("Screen devices support basic cards and other visual responses!"));
     
    } else {
        responseBuilder
    .add("Ok, no problem.");
     
    }
      responseBuilder
    .add("What else would you like to try?");
      responseBuilder
    .addSuggestions(
         
    new String[] {
           
    "Current capabilities", "Transfer surface",
         
    });
     
    return responseBuilder.build();
    }

    下記の JSON は Webhook リクエストを示します。

    {
     
    "responseId": "94b74485-cd7a-4b3b-b96a-fec15f3a496c-712767ed",
     
    "queryResult": {
       
    "queryText": "actions_intent_NEW_SURFACE",
       
    "parameters": {},
       
    "allRequiredParamsPresent": true,
       
    "fulfillmentText": "Webhook failed for intent: Transfer Surface - NEW_SURFACE",
       
    "fulfillmentMessages": [
         
    {
           
    "text": {
             
    "text": [
               
    "Webhook failed for intent: Transfer Surface - NEW_SURFACE"
             
    ]
           
    }
         
    }
       
    ],
       
    "outputContexts": [
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_capability_screen_output"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_capability_web_browser"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_capability_audio_output"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_capability_media_response_audio"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_capability_account_linking"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/google_assistant_input_type_voice"
         
    },
         
    {
           
    "name": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q/contexts/actions_intent_new_surface",
           
    "parameters": {
             
    "NEW_SURFACE": {
               
    "@type": "type.googleapis.com/google.actions.v2.NewSurfaceValue",
               
    "status": "OK"
             
    },
             
    "text": ""
           
    }
         
    }
       
    ],
       
    "intent": {
         
    "name": "projects/df-surface-caps-kohler/agent/intents/9db3798d-bdac-4dc8-a8e7-52349a3af0e8",
         
    "displayName": "Transfer Surface - NEW_SURFACE"
       
    },
       
    "intentDetectionConfidence": 1,
       
    "languageCode": "en"
     
    },
     
    "originalDetectIntentRequest": {
       
    "source": "google",
       
    "version": "2",
       
    "payload": {
         
    "user": {
           
    "locale": "en-US",
           
    "userVerificationStatus": "VERIFIED"
         
    },
         
    "conversation": {
           
    "conversationId": "ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q",
           
    "type": "ACTIVE",
           
    "conversationToken": "[]"
         
    },
         
    "inputs": [
           
    {
             
    "intent": "actions.intent.NEW_SURFACE",
             
    "rawInputs": [
               
    {
                 
    "inputType": "VOICE"
               
    }
             
    ],
             
    "arguments": [
               
    {
                 
    "name": "NEW_SURFACE",
                 
    "extension": {
                   
    "@type": "type.googleapis.com/google.actions.v2.NewSurfaceValue",
                   
    "status": "OK"
                 
    }
               
    },
               
    {
                 
    "name": "text"
               
    }
             
    ]
           
    }
         
    ],
         
    "surface": {
           
    "capabilities": [
             
    {
               
    "name": "actions.capability.SCREEN_OUTPUT"
             
    },
             
    {
               
    "name": "actions.capability.WEB_BROWSER"
             
    },
             
    {
               
    "name": "actions.capability.AUDIO_OUTPUT"
             
    },
             
    {
               
    "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
             
    },
             
    {
               
    "name": "actions.capability.ACCOUNT_LINKING"
             
    }
           
    ]
         
    },
         
    "availableSurfaces": [
           
    {
             
    "capabilities": [
               
    {
                 
    "name": "actions.capability.SCREEN_OUTPUT"
               
    },
               
    {
                 
    "name": "actions.capability.WEB_BROWSER"
               
    },
               
    {
                 
    "name": "actions.capability.AUDIO_OUTPUT"
               
    }
             
    ]
           
    }
         
    ]
       
    }
     
    },
     
    "session": "projects/df-surface-caps-kohler/agent/sessions/ABwppHEfQy-JgH7nmiW5gHWiDEyvqNRSPv9zkd3qTVF7F8G8YXJFI2_yal335Co0Z-_N5oUBTmVO_DJUlQONqd5lUgZz-Q"
    }

    下記の JSON は Webhook リクエストを示します。

    {
     
    "user": {
       
    "locale": "en-US",
       
    "userVerificationStatus": "VERIFIED"
     
    },
     
    "conversation": {
       
    "conversationId": "ABwppHENAOzBH5swn9iKb5QgUliTw4JLu5f86gS373tGtNvYcz1C3qHdorjcIb77o_PUleXGzIEFdPsl3-kmIAARvx67A7Ym",
       
    "type": "NEW"
     
    },
     
    "inputs": [
       
    {
         
    "intent": "actions.intent.NEW_SURFACE",
         
    "rawInputs": [
           
    {
             
    "inputType": "VOICE"
           
    }
         
    ],
         
    "arguments": [
           
    {
             
    "name": "NEW_SURFACE",
             
    "extension": {
               
    "@type": "type.googleapis.com/google.actions.v2.NewSurfaceValue",
               
    "status": "OK"
             
    }
           
    },
           
    {
             
    "name": "text"
           
    }
         
    ]
       
    }
     
    ],
     
    "surface": {
       
    "capabilities": [
         
    {
           
    "name": "actions.capability.SCREEN_OUTPUT"
         
    },
         
    {
           
    "name": "actions.capability.ACCOUNT_LINKING"
         
    },
         
    {
           
    "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
         
    },
         
    {
           
    "name": "actions.capability.AUDIO_OUTPUT"
         
    },
         
    {
           
    "name": "actions.capability.WEB_BROWSER"
         
    }
       
    ]
     
    },
     
    "availableSurfaces": [
       
    {
         
    "capabilities": [
           
    {
             
    "name": "actions.capability.WEB_BROWSER"
           
    },
           
    {
             
    "name": "actions.capability.AUDIO_OUTPUT"
           
    },
           
    {
             
    "name": "actions.capability.SCREEN_OUTPUT"
           
    }
         
    ]
       
    }
     
    ]
    }