시각적 선택 응답

작업을 계속 진행하기 위해 사용자가 여러 옵션 중 하나를 선택하도록 하려면 시각적 선택 응답을 사용하세요. 프롬프트의 일부로 다음과 같은 시각적 선택 응답 유형을 사용할 수 있습니다.

  • 목록
  • 컬렉션
  • 컬렉션 탐색

시각적 선택 응답을 정의할 때 Google 어시스턴트가 지원되는 기기에서만 응답을 반환하도록 RICH_RESPONSE 노출 영역 기능이 있는 후보를 사용하세요. 프롬프트의 content 객체당 하나의 리치 응답만 사용할 수 있습니다.

시각적 선택 응답 추가

시각적 선택 응답은 장면의 슬롯 채우기를 사용하여 사용자가 선택할 수 있는 옵션을 표시하고 선택된 항목을 처리합니다. 사용자가 항목을 선택하면 어시스턴트는 선택된 항목 값을 웹훅에 인수로 전달합니다. 그런 다음 인수 값에서 선택된 항목의 키를 수신합니다.

시각적 선택 응답을 사용하려면 먼저 사용자가 나중에 선택하는 응답을 나타내는 유형을 정의해야 합니다. 웹훅에서 이 유형을 선택하여 표시할 콘텐츠로 재정의합니다.

Actions Builder의 장면에 시각적 선택 응답을 추가하려면 다음 단계를 따르세요.

  1. 장면에서 슬롯 채우기 섹션에 슬롯을 추가합니다.
  2. 시각적 선택 응답에 대해 이전에 정의된 유형을 선택하고 이름을 지정합니다. 웹훅에서 이 슬롯 이름을 사용하여 나중에 유형을 참조합니다.
  3. 웹훅 호출 체크박스를 선택하고 시각적 선택 응답에 사용할 웹훅의 이벤트 핸들러 이름을 제공합니다.
  4. 메시지 보내기 체크박스를 선택합니다.
  5. 프롬프트에서 반환하려는 시각적 선택 응답에 따라 적절한 JSON 또는 YAML 콘텐츠를 제공합니다.
  6. 웹훅에서 선택한 항목 처리의 단계를 따릅니다.

사용 가능한 프롬프트 속성과 유형 재정의 예는 아래의 목록, 컬렉션, 컬렉션 탐색 섹션을 참조하세요.

선택된 항목 처리

시각적 선택 응답을 위해서는 웹훅 코드에서 사용자 선택을 처리해야 합니다. 사용자가 시각적 선택 응답에서 무언가를 선택하면 Google 어시스턴트는 그 값으로 슬롯을 채웁니다.

다음 예에서는 웹훅 코드가 선택된 옵션을 수신하고 변수에 저장합니다.

Node.js

app.handle('Option', conv => {
  // Note: 'prompt_option' is the name of the slot.
  const selectedOption = conv.session.params.prompt_option;
  conv.add(`You selected ${selectedOption}.`);
});

JSON

{
  "responseJson": {
    "session": {
      "id": "session_id",
      "params": {
        "prompt_option": "ITEM_1"
      }
    },
    "prompt": {
      "override": false,
      "firstSimple": {
        "speech": "You selected ITEM_1.",
        "text": "You selected ITEM_1."
      }
    }
  }
}

목록

휴대기기의 목록 선택 응답의 예

목록은 사용자에게 여러 항목으로 구성된 세로 목록을 표시하고 터치 또는 음성 입력을 통해 하나를 선택할 수 있도록 합니다. 사용자가 목록에서 항목을 선택하면 어시스턴트는 목록 항목의 제목이 포함된 사용자 쿼리 (채팅 풍선)를 생성합니다.

목록은 옵션을 구별하는 것이 중요하거나 사용자가 전체를 스캔해야 하는 옵션 중에서 선택해야 하는 경우에 적합합니다. 예를 들어 피터 존스와 피터 한스 중 어떤 '피터'에게 말해야 할까요?

목록에는 2~30개의 목록 항목이 포함되어야 합니다. 처음에 표시되는 요소 수는 사용자 기기에 따라 다르며 일반적인 시작 숫자는 10개 항목입니다.

목록 만들기

목록을 만들 때 프롬프트에는 사용자가 선택할 수 있는 각 항목의 키만 포함됩니다. 웹훅에서 Entry 유형에 따라 이러한 키에 해당하는 항목을 정의합니다.

Entry 객체로 정의된 목록 항목에는 다음과 같은 표시 특성이 있습니다.

  • 제목
    • 글꼴 및 글꼴 크기 고정
    • 최대 길이: 1줄 (생략 기호로 잘림...)
    • 음성 선택을 지원하기 위해 고유해야 합니다.
  • 설명(선택사항)
    • 글꼴 및 글꼴 크기 고정
    • 최대 길이: 2줄 (생략 기호로 잘림...)
  • 이미지(선택사항)
    • 크기: 48x48픽셀

시각적 선택 응답을 사용하려면 TYPE_REPLACE 모드에서 런타임 유형을 사용하여 슬롯 이름으로 유형을 재정의해야 합니다. 웹훅 이벤트 핸들러에서 name 속성의 슬롯 이름 (선택 응답 추가에 정의됨)으로 재정의할 유형을 참조합니다.

유형을 덮어쓴 후 결과 유형은 사용자가 어시스턴트 표시 중에서 선택할 수 있는 항목의 목록을 나타냅니다.

속성

목록 응답 유형에는 다음과 같은 속성이 있습니다.

속성 유형 요구 사항 설명
items ListItem의 배열 필수 목록에서 사용자가 선택할 수 있는 항목을 나타냅니다. 각 ListItem에는 목록 항목의 참조된 유형에 매핑되는 키가 포함됩니다.
title string 선택사항 목록의 일반 텍스트 제목이며 한 줄로 제한됩니다. 제목을 지정하지 않으면 카드 높이가 접힙니다.
subtitle string 선택사항 목록의 일반 텍스트 부제목입니다.

샘플 코드

다음 샘플은 웹훅 코드 또는 JSON webhookResponse에서 프롬프트 콘텐츠를 정의합니다. 그러나 대신 Actions Builder에서 프롬프트 콘텐츠 (YAML 또는 JSON)를 정의할 수도 있습니다.

Node.js

const ASSISTANT_LOGO_IMAGE = new Image({
  url: 'https://developers.google.com/assistant/assistant_96.png',
  alt: 'Google Assistant logo'
});

app.handle('List', conv => {
  conv.add('This is a list.');

  // Override type based on slot 'prompt_option'
  conv.session.typeOverrides = [{
    name: 'prompt_option',
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item'],
          display: {
             title: 'Item #1',
             description: 'Description of Item #1',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item'],
          display: {
             title: 'Item #2',
             description: 'Description of Item #2',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item'],
          display: {
             title: 'Item #3',
             description: 'Description of Item #3',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item'],
          display: {
             title: 'Item #4',
             description: 'Description of Item #4',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        ]
    }
  }];

  // Define prompt content using keys
  conv.add(new List({
    title: 'List title',
    subtitle: 'List subtitle',
    items: [
      {
        key: 'ITEM_1'
      },
      {
        key: 'ITEM_2'
      },
      {
        key: 'ITEM_3'
      },
      {
        key: 'ITEM_4'
      }
    ],
  }));
});

JSON

{
 "responseJson": {
   "session": {
     "id": "session_id",
     "params": {},
     "typeOverrides": [
       {
         "name": "prompt_option",
         "synonym": {
           "entries": [
             {
               "name": "ITEM_1",
               "synonyms": [
                 "Item 1",
                 "First item"
               ],
               "display": {
                 "title": "Item #1",
                 "description": "Description of Item #1",
                 "image": {
                   "alt": "Google Assistant logo",
                   "height": 0,
                   "url": "https://developers.google.com/assistant/assistant_96.png",
                   "width": 0
                 }
               }
             },
             {
               "name": "ITEM_2",
               "synonyms": [
                 "Item 2",
                 "Second item"
               ],
               "display": {
                 "title": "Item #2",
                 "description": "Description of Item #2",
                 "image": {
                   "alt": "Google Assistant logo",
                   "height": 0,
                   "url": "https://developers.google.com/assistant/assistant_96.png",
                   "width": 0
                 }
               }
             },
             {
               "name": "ITEM_3",
               "synonyms": [
                 "Item 3",
                 "Third item"
               ],
               "display": {
                 "title": "Item #3",
                 "description": "Description of Item #3",
                 "image": {
                   "alt": "Google Assistant logo",
                   "height": 0,
                   "url": "https://developers.google.com/assistant/assistant_96.png",
                   "width": 0
                 }
               }
             },
             {
               "name": "ITEM_4",
               "synonyms": [
                 "Item 4",
                 "Fourth item"
               ],
               "display": {
                 "title": "Item #4",
                 "description": "Description of Item #4",
                 "image": {
                   "alt": "Google Assistant logo",
                   "height": 0,
                   "url": "https://developers.google.com/assistant/assistant_96.png",
                   "width": 0
                 }
               }
             }
           ]
         },
         "typeOverrideMode": "TYPE_REPLACE"
       }
     ]
   },
   "prompt": {
     "override": false,
     "content": {
       "list": {
         "items": [
           {
             "key": "ITEM_1"
           },
           {
             "key": "ITEM_2"
           },
           {
             "key": "ITEM_3"
           },
           {
             "key": "ITEM_4"
           }
         ],
         "subtitle": "List subtitle",
         "title": "List title"
       }
     },
     "firstSimple": {
       "speech": "This is a list.",
       "text": "This is a list."
     }
   }
 }
}

컬렉션

컬렉션은 가로로 스크롤되며 사용자가 터치 또는 음성 입력을 통해 하나의 항목을 선택할 수 있습니다. 컬렉션은 목록과 비교할 때 타일이 커서 더 풍부한 콘텐츠를 사용할 수 있습니다. 컬렉션을 구성하는 타일은 이미지가 있는 기본 카드와 유사합니다. 사용자가 컬렉션에서 항목을 선택하면 어시스턴트가 항목의 제목이 포함된 사용자 쿼리 (채팅 풍선)를 생성합니다.

컬렉션은 사용자에게 다양한 옵션이 제시되지만 목록 간에 직접 비교하지 않아도 되는 경우에 유용합니다. 목록을 시각적으로 스캔하고 음성으로 상호작용하기가 더 쉬우므로 일반적으로 컬렉션보다 목록을 사용하는 것이 좋습니다.

컬렉션은 2~10개의 타일을 포함해야 합니다. 디스플레이 지원 기기에서는 사용자가 왼쪽이나 오른쪽으로 스와이프하여 항목을 선택하기 전에 컬렉션의 카드를 스크롤할 수 있습니다.

컬렉션 만들기

컬렉션을 만들 때 프롬프트에는 사용자가 선택할 수 있는 각 항목의 키만 포함됩니다. 웹훅에서 Entry 유형에 따라 이러한 키에 해당하는 항목을 정의합니다.

Entry 객체로 정의된 컬렉션 항목의 표시 특성은 다음과 같습니다.

  • 이미지(선택사항)
    • 이미지의 너비는 128dp, 너비 232dp가 됩니다.
    • 이미지의 가로세로 비율이 이미지 경계 상자와 일치하지 않으면 이미지의 중앙이 양쪽에 막대로 표시됩니다.
    • 이미지 링크가 깨지면 자리표시자 이미지가 대신 사용됩니다.
  • 제목 (필수 항목)
    • 일반 텍스트, 마크다운은 지원되지 않습니다. 기본 카드 리치 응답과 동일한 형식 지정 옵션
    • 제목을 지정하지 않으면 카드 높이가 접힙니다.
    • 음성 선택을 지원하기 위해 고유해야 합니다.
  • 설명(선택사항)
    • 일반 텍스트, 마크다운은 지원되지 않습니다. 기본 카드 리치 응답과 동일한 형식 지정 옵션

시각적 선택 응답을 사용하려면 TYPE_REPLACE 모드에서 런타임 유형을 사용하여 슬롯 이름으로 유형을 재정의해야 합니다. 웹훅 이벤트 핸들러에서 name 속성의 슬롯 이름 (선택 응답 추가에 정의됨)으로 재정의할 유형을 참조합니다.

유형을 덮어쓴 후 결과 유형은 사용자가 어시스턴트 표시 중에서 선택할 수 있는 항목의 모음을 나타냅니다.

속성

컬렉션 응답 유형에는 다음과 같은 속성이 있습니다.

속성 유형 요구 사항 설명
items CollectionItem의 배열 필수 사용자가 선택할 수 있는 컬렉션의 항목을 나타냅니다. 각 CollectionItem에는 컬렉션 항목의 참조된 유형에 매핑되는 키가 포함됩니다.
title string 선택사항 컬렉션의 일반 텍스트 제목입니다. 음성 선택을 지원하려면 제목이 컬렉션 내에서 고유해야 합니다.
subtitle string 선택사항 컬렉션의 일반 텍스트 부제목입니다.
image_fill ImageFill 선택사항 이미지의 가로세로 비율이 이미지 컨테이너의 가로세로 비율과 일치하지 않을 때 사용할 카드와 이미지 컨테이너 사이의 테두리입니다.

샘플 코드

다음 샘플은 웹훅 코드 또는 JSON 웹훅 응답에서 프롬프트 콘텐츠를 정의합니다. 그러나 대신 Actions Builder에서 프롬프트 콘텐츠 (YAML 또는 JSON)를 정의할 수도 있습니다.

Node.js

const ASSISTANT_LOGO_IMAGE = new Image({
  url: 'https://developers.google.com/assistant/assistant_96.png',
  alt: 'Google Assistant logo'
});

app.handle('Collection', conv => {
  conv.add("This is a collection.");

  // Override type based on slot 'prompt_option'
  conv.session.typeOverrides = [{
    name: 'prompt_option',
    mode: 'TYPE_REPLACE',
    synonym: {
      entries: [
        {
          name: 'ITEM_1',
          synonyms: ['Item 1', 'First item'],
          display: {
             title: 'Item #1',
             description: 'Description of Item #1',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_2',
          synonyms: ['Item 2', 'Second item'],
          display: {
             title: 'Item #2',
             description: 'Description of Item #2',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_3',
          synonyms: ['Item 3', 'Third item'],
          display: {
             title: 'Item #3',
             description: 'Description of Item #3',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        {
          name: 'ITEM_4',
          synonyms: ['Item 4', 'Fourth item'],
          display: {
             title: 'Item #4',
             description: 'Description of Item #4',
             image: ASSISTANT_LOGO_IMAGE,
                }
        },
        ]
    }
  }];

  // Define prompt content using keys
  conv.add(new Collection({
    title: 'Collection Title',
    subtitle: 'Collection subtitle',
    items: [
      {
        key: 'ITEM_1'
      },
      {
        key: 'ITEM_2'
      },
      {
        key: 'ITEM_3'
      },
      {
        key: 'ITEM_4'
      }
    ],
  }));
});

JSON

{
  "responseJson": {
    "session": {
      "id": "ABwppHHz--uQEEy3CCOANyB0J58oF2Yw5JEX0oXwit3uxDlRwzbEIK3Bcz7hXteE6hWovrLX9Ahpqu8t-jYnQRFGpAUqSuYjZ70",
      "params": {},
      "typeOverrides": [
        {
          "name": "prompt_option",
          "synonym": {
            "entries": [
              {
                "name": "ITEM_1",
                "synonyms": [
                  "Item 1",
                  "First item"
                ],
                "display": {
                  "title": "Item #1",
                  "description": "Description of Item #1",
                  "image": {
                    "alt": "Google Assistant logo",
                    "height": 0,
                    "url": "https://developers.google.com/assistant/assistant_96.png",
                    "width": 0
                  }
                }
              },
              {
                "name": "ITEM_2",
                "synonyms": [
                  "Item 2",
                  "Second item"
                ],
                "display": {
                  "title": "Item #2",
                  "description": "Description of Item #2",
                  "image": {
                    "alt": "Google Assistant logo",
                    "height": 0,
                    "url": "https://developers.google.com/assistant/assistant_96.png",
                    "width": 0
                  }
                }
              },
              {
                "name": "ITEM_3",
                "synonyms": [
                  "Item 3",
                  "Third item"
                ],
                "display": {
                  "title": "Item #3",
                  "description": "Description of Item #3",
                  "image": {
                    "alt": "Google Assistant logo",
                    "height": 0,
                    "url": "https://developers.google.com/assistant/assistant_96.png",
                    "width": 0
                  }
                }
              },
              {
                "name": "ITEM_4",
                "synonyms": [
                  "Item 4",
                  "Fourth item"
                ],
                "display": {
                  "title": "Item #4",
                  "description": "Description of Item #4",
                  "image": {
                    "alt": "Google Assistant logo",
                    "height": 0,
                    "url": "https://developers.google.com/assistant/assistant_96.png",
                    "width": 0
                  }
                }
              }
            ]
          },
          "typeOverrideMode": "TYPE_REPLACE"
        }
      ]
    },
    "prompt": {
      "override": false,
      "content": {
        "collection": {
          "imageFill": "UNSPECIFIED",
          "items": [
            {
              "key": "ITEM_1"
            },
            {
              "key": "ITEM_2"
            },
            {
              "key": "ITEM_3"
            },
            {
              "key": "ITEM_4"
            }
          ],
          "subtitle": "Collection subtitle",
          "title": "Collection Title"
        }
      },
      "firstSimple": {
        "speech": "This is a collection.",
        "text": "This is a collection."
      }
    }
  }
}

컬렉션 탐색

컬렉션과 마찬가지로 컬렉션 탐색은 사용자가 옵션 카드를 스크롤할 수 있는 리치 응답입니다. 컬렉션 탐색은 웹 콘텐츠용으로 특별히 설계되었으며 웹브라우저 (또는 모든 타일에 AMP가 사용 설정된 경우 AMP 브라우저)에서 선택한 타일을 엽니다.

컬렉션 탐색 응답에는 2~10개의 타일이 포함됩니다. 디스플레이 지원 기기에서는 사용자가 항목을 선택하기 전에 위 또는 아래로 스와이프하여 카드를 스크롤할 수 있습니다.

컬렉션 탐색 만들기

컬렉션 탐색을 만들 때 사용자가 이 프롬프트와 상호작용하는 방식을 고려하세요. 각 컬렉션 탐색 item는 정의된 URL을 열므로 사용자에게 유용한 세부정보를 제공합니다.

컬렉션 탐색 항목에는 다음과 같은 표시 특성이 있습니다.

  • 이미지(선택사항)
    • 이미지의 가로 128dp, 너비 232dp로 강제 설정됩니다.
    • 이미지의 가로세로 비율이 이미지 경계 상자와 일치하지 않으면 이미지가 측면 또는 상단과 하단에 막대로 가운데에 배치됩니다. 막대의 색상은 컬렉션 탐색 ImageFill 속성에 따라 결정됩니다.
    • 이미지 링크가 깨지면 자리표시자 이미지가 대신 사용됩니다.
  • 제목 (필수 항목)
    • 일반 텍스트, 마크다운은 지원되지 않습니다. 기본 카드 리치 응답과 동일한 형식이 사용됩니다.
    • 제목이 정의되지 않은 경우 카드 높이가 접힙니다.
  • 설명(선택사항)
  • 바닥글(선택사항)
    • 일반 텍스트. 마크다운은 지원되지 않습니다.

속성

컬렉션 탐색 응답 유형에는 다음과 같은 속성이 있습니다.

속성 유형 요구 사항 설명
item 객체 필수 사용자가 선택할 수 있는 컬렉션의 항목을 나타냅니다.
image_fill ImageFill 선택사항 이미지의 가로세로 비율이 이미지 컨테이너의 가로세로 비율과 일치하지 않을 때 사용할 카드와 이미지 컨테이너 사이의 테두리입니다.

컬렉션 탐색 item에는 다음과 같은 속성이 있습니다.

속성 유형 요구 사항 설명
title string 필수 컬렉션 항목의 일반 텍스트 제목입니다.
description string 선택사항 컬렉션 항목의 설명입니다.
footer string 선택사항 설명 아래에 표시되는 컬렉션 항목의 바닥글 텍스트입니다.
image Image 선택사항 컬렉션 항목에 표시되는 이미지입니다.
openUriAction OpenUrl 필수 컬렉션 항목이 선택되었을 때 열리는 URI입니다.

샘플 코드

다음 샘플은 웹훅 코드 또는 JSON 웹훅 응답에서 프롬프트 콘텐츠를 정의합니다. 그러나 대신 Actions Builder에서 프롬프트 콘텐츠 (YAML 또는 JSON)를 정의할 수도 있습니다.

YAML

candidates:
  - first_simple:
      variants:
        - speech: This is a collection browse.
    content:
      collection_browse:
        items:
          - title: Item #1
            description: Description of Item #1
            footer: Footer of Item #1
            image:
              url: 'https://developers.google.com/assistant/assistant_96.png'
            open_uri_action:
              url: 'https://www.example.com'
          - title: Item #2
            description: Description of Item #2
            footer: Footer of Item #2
            image:
              url:  'https://developers.google.com/assistant/assistant_96.png'
            open_uri_action:
              url: 'https://www.example.com'
        image_fill: WHITE

JSON

{
 "candidates": [
   {
     "firstSimple": {
       "speech": "This is a collection browse.",
       "text": "This is a collection browse."
     },
     "content": {
       "collectionBrowse": {
         "items": [
           {
             "title": "Item #1",
             "description": "Description of Item #1",
             "footer": "Footer of Item #1",
             "image": {
               "url": "https://developers.google.com/assistant/assistant_96.png"
             },
             "openUriAction": {
               "url": "https://www.example.com"
             }
           },
           {
             "title": "Item #2",
             "description": "Description of Item #2",
             "footer": "Footer of Item #2",
             "image": {
               "url": "https://developers.google.com/assistant/assistant_96.png"
             },
             "openUriAction": {
               "url": "https://www.example.com"
             }
           }
         ],
         "imageFill": "WHITE"
       }
     }
   }
 ]
}

Node.js

// Collection Browse
app.handle('collectionBrowse', (conv) => {
  conv.add('This is a collection browse.');
  conv.add(new CollectionBrowse({
    'imageFill': 'WHITE',
    'items':
      [
        {
          'title': 'Item #1',
          'description': 'Description of Item #1',
          'footer': 'Footer of Item #1',
          'image': {
            'url': 'https://developers.google.com/assistant/assistant_96.png'
          },
          'openUriAction': {
            'url': 'https://www.example.com'
          }
        },
        {
          'title': 'Item #2',
          'description': 'Description of Item #2',
          'footer': 'Footer of Item #2',
          'image': {
            'url': 'https://developers.google.com/assistant/assistant_96.png'
          },
          'openUriAction': {
            'url': 'https://www.example.com'
          }
        }
      ]
  }));
});

JSON

{
  "responseJson": {
    "session": {
      "id": "session_id",
      "params": {},
      "languageCode": ""
    },
    "prompt": {
      "override": false,
      "content": {
        "collectionBrowse": {
          "imageFill": "WHITE",
          "items": [
            {
              "title": "Item #1",
              "description": "Description of Item #1",
              "footer": "Footer of Item #1",
              "image": {
                "url": "https://developers.google.com/assistant/assistant_96.png"
              },
              "openUriAction": {
                "url": "https://www.example.com"
              }
            },
            {
              "title": "Item #2",
              "description": "Description of Item #2",
              "footer": "Footer of Item #2",
              "image": {
                "url": "https://developers.google.com/assistant/assistant_96.png"
              },
              "openUriAction": {
                "url": "https://www.example.com"
              }
            }
          ]
        }
      },
      "firstSimple": {
        "speech": "This is a collection browse.",
        "text": "This is a collection browse."
      }
    }
  }
}