Khám phá trong Dialogflow
Nhấp vào Tiếp tục để nhập mẫu Phản hồi của chúng tôi vào Dialogflow. Sau đó, hãy làm theo các bước bên dưới để triển khai và kiểm thử mẫu:
- Nhập tên nhân viên hỗ trợ rồi tạo một nhân viên hỗ trợ Dialogflow mới cho mẫu.
- Sau khi nhập xong nhân viên hỗ trợ, hãy nhấp vào Chuyển đến nhân viên hỗ trợ.
- Trên trình đơn điều hướng chính, hãy chuyển đến mục Thực hiện đơn hàng.
- Bật Inline Editor (Trình chỉnh sửa cùng dòng), sau đó nhấp vào Deploy (Triển khai). Trình chỉnh sửa chứa mã mẫu.
- Trên trình đơn điều hướng chính, hãy chuyển đến phần Tích hợp, rồi nhấp vào Trợ lý Google.
- Trong cửa sổ phụ xuất hiện, hãy bật tính năng Auto-preview changes (Tự động xem trước các thay đổi) rồi nhấp vào Test (Kiểm thử) để mở Trình mô phỏng hành động.
- Trong trình mô phỏng, hãy nhập
Talk to my test app
để kiểm tra mẫu!
Sử dụng phản hồi chi tiết nếu bạn muốn hiển thị các phần tử hình ảnh để tăng cường mức độ tương tác của người dùng với Hành động của bạn. Các phần tử hình ảnh này có thể cung cấp gợi ý về cách tiếp tục một cuộc trò chuyện.
Phản hồi chi tiết có thể xuất hiện trong trải nghiệm chỉ màn hình hoặc trải nghiệm âm thanh và màn hình. Chúng có thể chứa các thành phần sau:
- Một hoặc hai câu trả lời đơn giản (bong bóng trò chuyện).
- Một thẻ cơ bản không bắt buộc.
- Khối đề xuất không bắt buộc.
- Một khối liên kết ra không bắt buộc.
Bạn cũng có thể xem nguyên tắc thiết kế cuộc trò chuyện để tìm hiểu cách kết hợp những thành phần hình ảnh này vào Hành động của mình.
Thuộc tính
Phản hồi nhiều định dạng có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có tính năng
actions.capability.SCREEN_OUTPUT
. - Mục đầu tiên trong câu trả lời nhiều định dạng phải là câu trả lời đơn giản.
- Tối đa là hai câu trả lời đơn giản.
- Tối đa một thẻ cơ bản hoặc
StructuredResponse
. - Tối đa 8 khối đề xuất.
- Không cho phép khối đề xuất trong
FinalResponse
- Tính năng liên kết ra web từ màn hình thông minh hiện chưa được hỗ trợ.
Các phần sau đây hướng dẫn bạn cách tạo nhiều loại câu trả lời nhiều định dạng.
Thẻ cơ bản
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/basic-card.png?authuser=7&hl=vi)
Thẻ cơ bản cho thấy thông tin có thể bao gồm:
- Bài đăng có hình ảnh
- Tiêu đề
- Tiêu đề phụ
- Nội dung văn bản
- Nút liên kết
- Border
Sử dụng thẻ cơ bản chủ yếu cho mục đích hiển thị. Các trang này được thiết kế ngắn gọn để trình bày thông tin chính (hoặc tóm tắt) cho người dùng, đồng thời cho phép người dùng tìm hiểu thêm nếu bạn muốn (sử dụng đường liên kết web).
Trong hầu hết trường hợp, bạn nên thêm khối đề xuất bên dưới các thẻ để tiếp tục hoặc chuyển hướng cuộc trò chuyện.
Tránh lặp lại thông tin hiển thị trong thẻ trong bong bóng trò chuyện bằng mọi giá.
Thuộc tính
Loại phản hồi thẻ cơ bản có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có tính năng
actions.capability.SCREEN_OUTPUT
. - Văn bản được định dạng (bắt buộc nếu không có hình ảnh)
- Theo mặc định, văn bản thuần tuý.
- Không được chứa đường liên kết.
- Giới hạn 10 dòng với một hình ảnh, 15 dòng đối với một hình ảnh. Đây là khoảng 500 ký tự (có hình ảnh) hoặc 750 (không có hình ảnh). Điện thoại màn hình nhỏ hơn cũng cắt ngắn văn bản sớm hơn điện thoại màn hình lớn hơn. Nếu văn bản chứa quá nhiều dòng, thì văn bản đó sẽ bị cắt ngắn ở ngắt từ cuối cùng bằng dấu ba chấm.
- Hỗ trợ một số ít thao tác đánh dấu:
- Dòng mới có dấu cách kép, theo sau là \n
**bold**
*italics*
- Hình ảnh (bắt buộc nếu không có văn bản đã định dạng)
- Tất cả hình ảnh đều phải có chiều cao là 192 dp.
- Nếu tỷ lệ khung hình của hình ảnh khác với màn hình, thì hình ảnh sẽ được đặt ở giữa bằng các thanh màu xám ở cạnh dọc hoặc ngang.
- Nguồn hình ảnh là một URL.
- Được phép sử dụng ảnh GIF chuyển động.
Không bắt buộc
- Tiêu đề
- Văn bản thuần tuý.
- Phông chữ và kích thước cố định.
- Tối đa một dòng; các ký tự thừa sẽ bị cắt bớt.
- Chiều cao thẻ sẽ thu gọn nếu bạn không chỉ định tiêu đề.
- Tiêu đề phụ
- Văn bản thuần tuý.
- Cố định phông chữ và cỡ chữ.
- Tối đa một dòng; các ký tự thừa sẽ bị cắt bớt.
- Chiều cao thẻ sẽ thu gọn nếu không có tiêu đề phụ nào được chỉ định.
- Nút liên kết
- Bắt buộc phải có tiêu đề liên kết
- Tối đa một đường liên kết
- Được phép liên kết đến các trang web bên ngoài miền của nhà phát triển.
- Văn bản liên kết không được gây hiểu lầm. Bạn sẽ thấy thông tin này trong quá trình phê duyệt.
- Thẻ cơ bản không có khả năng tương tác nếu không có đường liên kết. Khi nhấn vào đường liên kết, người dùng sẽ được đưa đến đường liên kết đó, còn phần nội dung chính của thẻ thì không hoạt động.
- Đường viền
- Bạn có thể điều chỉnh đường viền giữa thẻ và vùng chứa hình ảnh để tuỳ chỉnh cách trình bày thẻ cơ bản.
- Được định cấu hình bằng cách đặt thuộc tính chuỗi JSON
imageDisplayOptions
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/smart-display/basic-card.png?authuser=7&hl=vi)
Mã mẫu
Node.js
app.intent('Basic Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a basic card.`); conv.ask(new BasicCard({ text: `This is a basic card. Text in a basic card can include "quotes" and most other unicode characters including emojis. Basic cards also support some markdown formatting like *emphasis* or _italics_, **strong** or __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other things like line \nbreaks`, // Note the two spaces before '\n' required for // a line break to be rendered in the card. subtitle: 'This is a subtitle', title: 'Title: this is a title', buttons: new Button({ title: 'This is a button', url: 'https://assistant.google.com/', }), image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), display: 'CROPPED', })); conv.ask('Which response would you like to see next?'); });
Java
@ForIntent("Basic Card") public ActionResponse basicCard(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } // Prepare formatted text for card String text = "This is a basic card. Text in a basic card can include \"quotes\" and\n" + " most other unicode characters including emoji \uD83D\uDCF1. Basic cards also support\n" + " some markdown formatting like *emphasis* or _italics_, **strong** or\n" + " __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n" + " things like line \\nbreaks"; // Note the two spaces before '\n' required for // a line break to be rendered in the card. responseBuilder .add("Here's an example of a basic card.") .add( new BasicCard() .setTitle("Title: this is a title") .setSubtitle("This is a subtitle") .setFormattedText(text) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setImageDisplayOptions("CROPPED") .setButtons( new ArrayList<Button>( Arrays.asList( new Button() .setTitle("This is a Button") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))))) .add("Which response would you like to see next?"); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a basic card.`); conv.ask(new BasicCard({ text: `This is a basic card. Text in a basic card can include "quotes" and most other unicode characters including emojis. Basic cards also support some markdown formatting like *emphasis* or _italics_, **strong** or __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other things like line \nbreaks`, // Note the two spaces before '\n' required for // a line break to be rendered in the card. subtitle: 'This is a subtitle', title: 'Title: this is a title', buttons: new Button({ title: 'This is a button', url: 'https://assistant.google.com/', }), image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), display: 'CROPPED', })); conv.ask('Which response would you like to see next?');
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } // Prepare formatted text for card String text = "This is a basic card. Text in a basic card can include \"quotes\" and\n" + " most other unicode characters including emoji \uD83D\uDCF1. Basic cards also support\n" + " some markdown formatting like *emphasis* or _italics_, **strong** or\n" + " __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n" + " things like line \\nbreaks"; // Note the two spaces before '\n' required for // a line break to be rendered in the card. responseBuilder .add("Here's an example of a basic card.") .add( new BasicCard() .setTitle("Title: this is a title") .setSubtitle("This is a subtitle") .setFormattedText(text) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setImageDisplayOptions("CROPPED") .setButtons( new ArrayList<Button>( Arrays.asList( new Button() .setTitle("This is a Button") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))))) .add("Which response would you like to see next?"); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a basic card." } }, { "basicCard": { "title": "Title: this is a title", "subtitle": "This is a subtitle", "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emojis. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" }, "buttons": [ { "title": "This is a button", "openUrlAction": { "url": "https://assistant.google.com/" } } ], "imageDisplayOptions": "CROPPED" } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a basic card." } }, { "basicCard": { "title": "Title: this is a title", "subtitle": "This is a subtitle", "formattedText": "This is a basic card. Text in a basic card can include \"quotes\" and\n most other unicode characters including emojis. Basic cards also support\n some markdown formatting like *emphasis* or _italics_, **strong** or\n __bold__, and ***bold itallic*** or ___strong emphasis___ as well as other\n things like line \nbreaks", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" }, "buttons": [ { "title": "This is a button", "openUrlAction": { "url": "https://assistant.google.com/" } } ], "imageDisplayOptions": "CROPPED" } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } ] }
Băng chuyền duyệt web
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/browse-carousel.png?authuser=7&hl=vi)
Băng chuyền duyệt web là một phản hồi đa dạng thức cho phép người dùng cuộn theo chiều dọc và chọn một thẻ thông tin trong một bộ sưu tập. Băng chuyền duyệt web được thiết kế riêng cho nội dung web bằng cách mở ô đã chọn trong trình duyệt web (hoặc trình duyệt AMP nếu tất cả các ô đều hỗ trợ AMP). Băng chuyền duyệt web cũng nằm cố định trên giao diện Trợ lý của người dùng để duyệt xem sau.
Thuộc tính
Loại phản hồi băng chuyền duyệt web có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có cả tính năng
actions.capability.SCREEN_OUTPUT
vàactions.capability.WEB_BROWSER
. Loại phản hồi này hiện chưa có trên màn hình thông minh. - Băng chuyền duyệt web
- Tối đa 10 ô.
- Tối thiểu 2 ô.
- Tất cả các ô trong băng chuyền phải liên kết đến nội dung trên web (nên dùng nội dung AMP).
- Để người dùng được chuyển đến trình xem AMP, bạn phải đặt
urlHintType
trên ô nội dung AMP thành "AMP_CONTENT".
- Để người dùng được chuyển đến trình xem AMP, bạn phải đặt
- Duyệt qua ô băng chuyền
- Tính nhất quán của thẻ thông tin (bắt buộc):
- Tất cả ô trong một băng chuyền duyệt web phải có cùng thành phần. Ví dụ: nếu một thẻ thông tin có trường hình ảnh, thì phần còn lại của các thẻ thông tin trong băng chuyền cũng phải có trường hình ảnh.
- Nếu tất cả các ô trong băng chuyền duyệt web đều liên kết đến nội dung hỗ trợ AMP, thì người dùng sẽ được chuyển đến một trình duyệt AMP có chức năng bổ sung. Nếu có thẻ thông tin nào liên kết đến nội dung không phải AMP, thì tất cả thẻ thông tin sẽ chuyển người dùng đến một trình duyệt web.
- Hình ảnh (không bắt buộc)
- Hình ảnh bắt buộc phải có kích thước cao 128 dp x rộng 232 dp.
- Nếu tỷ lệ khung hình không khớp với hộp giới hạn hình ảnh, thì hình ảnh sẽ được căn giữa với các thanh ở hai bên. Trên điện thoại thông minh, hình ảnh được căn giữa theo hình vuông với các góc bo tròn.
- Nếu đường liên kết của hình ảnh bị hỏng, thì hệ thống sẽ sử dụng hình ảnh giữ chỗ.
- Văn bản thay thế là bắt buộc trên hình ảnh.
- Tiêu đề (bắt buộc)
- Tuỳ chọn định dạng giống như thẻ văn bản cơ bản.
- Tiêu đề phải là duy nhất (để hỗ trợ lựa chọn giọng nói).
- Tối đa 2 dòng văn bản.
- Cỡ chữ 16 sp.
- Nội dung mô tả (không bắt buộc)
- Tuỳ chọn định dạng giống như thẻ văn bản cơ bản.
- Tối đa 4 dòng văn bản.
- Bị cắt bớt bằng dấu ba chấm (...)
- Cỡ chữ 14 sp, màu xám.
- Chân trang (không bắt buộc)
- Cố định phông chữ và cỡ chữ.
- Tối đa một dòng văn bản.
- Bị cắt bớt bằng dấu ba chấm (...)
- Cố định ở dưới cùng nên các thẻ thông tin có ít dòng văn bản nội dung hơn có thể có khoảng trắng phía trên văn bản phụ.
- Cỡ chữ 14 sp, màu xám.
- Tính nhất quán của thẻ thông tin (bắt buộc):
- Tương tác
- Người dùng có thể cuộn theo chiều dọc để xem các mục.
- Thẻ nhấn: Nhấn vào một mục sẽ đưa người dùng đến một trình duyệt, hiển thị trang được liên kết.
- Nhập bằng giọng nói
- Hành vi của micrô
- Micrô không mở lại khi băng chuyền duyệt web được gửi đến người dùng.
- Người dùng vẫn có thể nhấn vào micrô hoặc gọi Trợ lý ("Ok Google") để mở lại micrô.
- Hành vi của micrô
Hướng dẫn
Theo mặc định, micrô vẫn đóng sau khi băng chuyền duyệt web được gửi đi. Nếu muốn tiếp tục cuộc trò chuyện sau đó, bạn nên thêm khối đề xuất bên dưới băng chuyền.
Đừng bao giờ lặp lại các lựa chọn có trong danh sách dưới dạng khối đề xuất. Các khối trong ngữ cảnh này được dùng để chuyển hướng cuộc trò chuyện (không phải để lựa chọn).
Tương tự như với danh sách, bong bóng trò chuyện đi kèm thẻ băng chuyền là một tập hợp con của âm thanh (TTS/SSML). Âm thanh (TTS/SSML) ở đây tích hợp thẻ thông tin đầu tiên trong băng chuyền và bạn cũng không nên đọc tất cả phần tử trên băng chuyền. Tốt nhất là nên đề cập đến mặt hàng đầu tiên và lý do tại sao mặt hàng đó xuất hiện (ví dụ: mặt hàng phổ biến nhất, mặt hàng được mua gần đây nhất, được nhắc đến nhiều nhất).
Mã mẫu
Node.js
app.intent('Browsing Carousel', (conv) => { if (!conv.screen || !conv.surface.capabilities.has('actions.capability.WEB_BROWSER')) { conv.ask('Sorry, try this on a phone or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a browsing carousel.`); conv.ask(new BrowseCarousel({ items: [ new BrowseCarouselItem({ title: 'Title of item 1', url: 'https://example.com', description: 'Description of item 1', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 1 footer', }), new BrowseCarouselItem({ title: 'Title of item 2', url: 'https://example.com', description: 'Description of item 2', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 2 footer', }), ], })); });
Java
@ForIntent("Browsing Carousel") public ActionResponse browseCarousel(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue()) || !request.hasCapability(Capability.WEB_BROWSER.getValue())) { return responseBuilder .add("Sorry, try this on a phone or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("Here's an example of a browsing carousel.") .add( new CarouselBrowse() .setItems( new ArrayList<CarouselBrowseItem>( Arrays.asList( new CarouselBrowseItem() .setTitle("Title of item 1") .setDescription("Description of item 1") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 1 footer"), new CarouselBrowseItem() .setTitle("Title of item 2") .setDescription("Description of item 2") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 2 footer"))))); return responseBuilder.build(); }
Node.js
if (!conv.screen || !conv.surface.capabilities.has('actions.capability.WEB_BROWSER')) { conv.ask('Sorry, try this on a phone or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask(`Here's an example of a browsing carousel.`); conv.ask(new BrowseCarousel({ items: [ new BrowseCarouselItem({ title: 'Title of item 1', url: 'https://example.com', description: 'Description of item 1', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 1 footer', }), new BrowseCarouselItem({ title: 'Title of item 2', url: 'https://example.com', description: 'Description of item 2', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Image alternate text', }), footer: 'Item 2 footer', }), ], }));
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue()) || !request.hasCapability(Capability.WEB_BROWSER.getValue())) { return responseBuilder .add("Sorry, try this on a phone or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("Here's an example of a browsing carousel.") .add( new CarouselBrowse() .setItems( new ArrayList<CarouselBrowseItem>( Arrays.asList( new CarouselBrowseItem() .setTitle("Title of item 1") .setDescription("Description of item 1") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 1 footer"), new CarouselBrowseItem() .setTitle("Title of item 2") .setDescription("Description of item 2") .setOpenUrlAction(new OpenUrlAction().setUrl("https://example.com")) .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Image alternate text")) .setFooter("Item 2 footer"))))); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a browsing carousel." } }, { "carouselBrowse": { "items": [ { "title": "Title of item 1", "openUrlAction": { "url": "https://example.com" }, "description": "Description of item 1", "footer": "Item 1 footer", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" } }, { "title": "Title of item 2", "openUrlAction": { "url": "https://example.com" }, "description": "Description of item 2", "footer": "Item 2 footer", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Image alternate text" } } ] } } ] } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "Here's an example of a browsing carousel." } }, { "carouselBrowse": { "items": [ { "description": "Description of item 1", "footer": "Item 1 footer", "image": { "accessibilityText": "Image alternate text", "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png" }, "openUrlAction": { "url": "https://example.com" }, "title": "Title of item 1" }, { "description": "Description of item 2", "footer": "Item 2 footer", "image": { "accessibilityText": "Image alternate text", "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png" }, "openUrlAction": { "url": "https://example.com" }, "title": "Title of item 2" } ] } } ] } }, "possibleIntents": [ { "intent": "actions.intent.TEXT" } ] } ] }
Xử lý mục đã chọn
Không cần phương thức thực hiện tiếp theo nào cho các hoạt động tương tác của người dùng với các mục trong băng chuyền duyệt xem, vì băng chuyền xử lý việc chuyển giao trình duyệt. Xin lưu ý rằng micrô sẽ không mở lại sau khi người dùng tương tác với một mục trong băng chuyền duyệt web. Vì vậy, bạn nên kết thúc cuộc trò chuyện hoặc đưa khối đề xuất vào phản hồi theo hướng dẫn ở trên.
Khối đề xuất
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/suggestions.png?authuser=7&hl=vi)
Sử dụng khối đề xuất để gợi ý câu trả lời nhằm tiếp tục hoặc chuyển hướng cuộc trò chuyện. Nếu có một lời kêu gọi hành động chính trong cuộc trò chuyện, hãy cân nhắc liệt kê lời kêu gọi đó làm khối đề xuất đầu tiên.
Bất cứ khi nào có thể, bạn nên đưa một đề xuất chính vào ô trò chuyện, nhưng chỉ làm vậy khi câu trả lời hoặc cuộc trò chuyện diễn ra tự nhiên.
Thuộc tính
Khối đề xuất có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có tính năng
actions.capability.SCREEN_OUTPUT
. - Để liên kết khối đề xuất với web, các nền tảng cũng phải có tính năng
actions.capability.WEB_BROWSER
. Tính năng này hiện không hoạt động trên màn hình thông minh. - Tối đa 8 khối.
- Độ dài văn bản tối đa là 25 ký tự.
Chỉ hỗ trợ văn bản thuần tuý.
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/smart-display/chips.png?authuser=7&hl=vi)
Mã mẫu
Node.js
app.intent('Suggestion Chips', (conv) => { if (!conv.screen) { conv.ask('Chips can be demonstrated on screen devices.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('These are suggestion chips.'); conv.ask(new Suggestions('Suggestion 1')); conv.ask(new Suggestions(['Suggestion 2', 'Suggestion 3'])); conv.ask(new LinkOutSuggestion({ name: 'Suggestion Link', url: 'https://assistant.google.com/', })); conv.ask('Which type of response would you like to see next?'); ; });
Java
@ForIntent("Suggestion Chips") public ActionResponse suggestionChips(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("These are suggestion chips.") .addSuggestions(new String[] {"Suggestion 1", "Suggestion 2", "Suggestion 3"}) .add( new LinkOutSuggestion() .setDestinationName("Suggestion Link") .setUrl("https://assistant.google.com/")) .add("Which type of response would you like to see next?"); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Chips can be demonstrated on screen devices.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('These are suggestion chips.'); conv.ask(new Suggestions('Suggestion 1')); conv.ask(new Suggestions(['Suggestion 2', 'Suggestion 3'])); conv.ask(new LinkOutSuggestion({ name: 'Suggestion Link', url: 'https://assistant.google.com/', })); conv.ask('Which type of response would you like to see next?');
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("These are suggestion chips.") .addSuggestions(new String[] {"Suggestion 1", "Suggestion 2", "Suggestion 3"}) .add( new LinkOutSuggestion() .setDestinationName("Suggestion Link") .setUrl("https://assistant.google.com/")) .add("Which type of response would you like to see next?"); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "These are suggestion chips." } }, { "simpleResponse": { "textToSpeech": "Which type of response would you like to see next?" } } ], "suggestions": [ { "title": "Suggestion 1" }, { "title": "Suggestion 2" }, { "title": "Suggestion 3" } ], "linkOutSuggestion": { "destinationName": "Suggestion Link", "url": "https://assistant.google.com/" } } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "These are suggestion chips." } }, { "simpleResponse": { "textToSpeech": "Which type of response would you like to see next?" } } ], "suggestions": [ { "title": "Suggestion 1" }, { "title": "Suggestion 2" }, { "title": "Suggestion 3" } ], "linkOutSuggestion": { "destinationName": "Suggestion Link", "url": "https://assistant.google.com/" } } } } ] }
Phản hồi của nội dung nghe nhìn
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/media.png?authuser=7&hl=vi)
Các phản hồi của nội dung đa phương tiện cho phép Hành động của bạn phát nội dung âm thanh có thời lượng phát dài hơn giới hạn 240 giây của SSML. Thành phần chính của phản hồi nội dung đa phương tiện là thẻ theo dõi đơn. Thẻ này cho phép người dùng thực hiện các thao tác sau:
- Phát lại 10 giây trước.
- Tua đi trong 30 giây.
- Xem tổng thời lượng của nội dung nghe nhìn.
- Xem chỉ báo tiến trình phát âm thanh.
- Xem thời gian phát đã trôi qua.
Phản hồi của nội dung nghe nhìn hỗ trợ các chế độ điều khiển âm thanh sau đây để tương tác bằng giọng nói:
- “Ok Google, phát”.
- “Ok Google, tạm dừng.”
- “Ok Google, dừng lại”.
- “Ok Google, hãy bắt đầu lại.”
Người dùng cũng có thể điều khiển âm lượng bằng cách nói các cụm từ như "Ok Google, tăng âm lượng". hoặc "Ok Google, đặt âm lượng ở mức 50%". Các ý định trong Hành động của bạn sẽ được ưu tiên nếu chúng xử lý các cụm từ huấn luyện tương tự. Hãy để Trợ lý xử lý những yêu cầu này của người dùng, trừ phi Hành động của bạn có lý do cụ thể.
Thuộc tính
Phản hồi của nội dung đa phương tiện có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có chức năng
actions.capability.MEDIA_RESPONSE_AUDIO
. - Âm thanh để phát phải thuộc tệp
.mp3
có định dạng chính xác. Không hỗ trợ phát trực tiếp. - Tệp nội dung nghe nhìn để phát phải được chỉ định là một URL loại HTTPS.
- Hình ảnh (không bắt buộc)
- Bạn có thể cung cấp biểu tượng hoặc hình ảnh nếu muốn.
- Biểu tượng
- Biểu tượng của bạn xuất hiện dưới dạng hình thu nhỏ không đường viền ở bên phải thẻ trình phát nội dung đa phương tiện.
- Kích thước phải là 36 x 36 dp. Hình ảnh có kích thước lớn hơn sẽ được đổi kích thước cho vừa.
- Hình ảnh
- Vùng chứa hình ảnh sẽ có chiều cao là 192 dp.
- Hình ảnh của bạn xuất hiện ở đầu thẻ trình phát nội dung đa phương tiện và trải dài toàn bộ chiều rộng của thẻ. Hầu hết hình ảnh sẽ xuất hiện cùng với các thanh dọc theo đầu hoặc hai cạnh.
- Được phép sử dụng ảnh GIF chuyển động.
- Bạn phải chỉ định nguồn hình ảnh dưới dạng URL.
- Văn bản thay thế là bắt buộc trên tất cả hình ảnh.
Hành vi trên nền tảng
Tính năng phản hồi nội dung nghe nhìn được hỗ trợ trên điện thoại Android và trên Google Home. Hành vi của các phản hồi nội dung đa phương tiện phụ thuộc vào nền tảng mà người dùng tương tác với Hành động của bạn.
Trên điện thoại Android, người dùng có thể xem nội dung đa phương tiện phản hồi khi đáp ứng bất kỳ điều kiện nào sau đây:
- Trợ lý Google đang chạy ở nền trước và màn hình điện thoại đang bật.
- Người dùng rời khỏi Trợ lý Google trong khi âm thanh đang phát và quay lại Trợ lý Google trong vòng 10 phút kể từ khi phát xong. Khi quay lại Trợ lý Google, người dùng sẽ thấy thẻ nội dung đa phương tiện và khối đề xuất.
- Trợ lý cho phép người dùng điều khiển âm lượng thiết bị trong Hành động trò chuyện bằng cách nói những câu như "tăng âm lượng" hoặc "đặt âm lượng ở mức 50 phần trăm". Nếu bạn có các ý định xử lý các cụm từ huấn luyện tương tự, thì ý định sẽ được ưu tiên. Bạn nên cho phép Trợ lý xử lý các yêu cầu này của người dùng, trừ phi Hành động của bạn có lý do cụ thể.
Bạn có thể sử dụng các nút điều khiển nội dung nghe nhìn trong khi điện thoại đang khoá. Trên Android, các nút điều khiển cũng xuất hiện trong khu vực thông báo.
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/smart-display/media.png?authuser=7&hl=vi)
Mã mẫu
Mã mẫu sau đây cho biết cách bạn có thể cập nhật phản hồi nhiều định dạng để thêm nội dung nghe nhìn.
Node.js
app.intent('Media Response', (conv) => { if (!conv.surface.capabilities .has('actions.capability.MEDIA_RESPONSE_AUDIO')) { conv.ask('Sorry, this device does not support audio playback.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a media response example.'); conv.ask(new MediaObject({ name: 'Jazz in Paris', url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3', description: 'A funky Jazz tune', icon: new Image({ url: 'https://storage.googleapis.com/automotive-media/album_art.jpg', alt: 'Album cover of an ocean view', }), })); conv.ask(new Suggestions(['Basic Card', 'List', 'Carousel', 'Browsing Carousel'])); });
Java
@ForIntent("Media Response") public ActionResponse mediaResponse(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue())) { return responseBuilder .add("Sorry, this device does not support audio playback.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a media response example.") .add( new MediaResponse() .setMediaObjects( new ArrayList<MediaObject>( Arrays.asList( new MediaObject() .setName("Jazz in Paris") .setDescription("A funky Jazz tune") .setContentUrl( "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3") .setIcon( new Image() .setUrl( "https://storage.googleapis.com/automotive-media/album_art.jpg") .setAccessibilityText("Album cover of an ocean view"))))) .setMediaType("AUDIO")) .addSuggestions(new String[] {"Basic Card", "List", "Carousel", "Browsing Carousel"}); return responseBuilder.build(); }
Node.js
if (!conv.surface.capabilities .has('actions.capability.MEDIA_RESPONSE_AUDIO')) { conv.ask('Sorry, this device does not support audio playback.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a media response example.'); conv.ask(new MediaObject({ name: 'Jazz in Paris', url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3', description: 'A funky Jazz tune', icon: new Image({ url: 'https://storage.googleapis.com/automotive-media/album_art.jpg', alt: 'Album cover of an ocean view', }), })); conv.ask(new Suggestions(['Basic Card', 'List', 'Carousel', 'Browsing Carousel']));
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.MEDIA_RESPONSE_AUDIO.getValue())) { return responseBuilder .add("Sorry, this device does not support audio playback.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a media response example.") .add( new MediaResponse() .setMediaObjects( new ArrayList<MediaObject>( Arrays.asList( new MediaObject() .setName("Jazz in Paris") .setDescription("A funky Jazz tune") .setContentUrl( "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3") .setIcon( new Image() .setUrl( "https://storage.googleapis.com/automotive-media/album_art.jpg") .setAccessibilityText("Album cover of an ocean view"))))) .setMediaType("AUDIO")) .addSuggestions(new String[] {"Basic Card", "List", "Carousel", "Browsing Carousel"}); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a media response example." } }, { "mediaResponse": { "mediaType": "AUDIO", "mediaObjects": [ { "contentUrl": "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3", "description": "A funky Jazz tune", "icon": { "url": "https://storage.googleapis.com/automotive-media/album_art.jpg", "accessibilityText": "Album cover of an ocean view" }, "name": "Jazz in Paris" } ] } } ], "suggestions": [ { "title": "Basic Card" }, { "title": "List" }, { "title": "Carousel" }, { "title": "Browsing Carousel" } ] } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a media response example." } }, { "mediaResponse": { "mediaType": "AUDIO", "mediaObjects": [ { "contentUrl": "https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3", "description": "A funky Jazz tune", "icon": { "url": "https://storage.googleapis.com/automotive-media/album_art.jpg", "accessibilityText": "Album cover of an ocean view" }, "name": "Jazz in Paris" } ] } } ], "suggestions": [ { "title": "Basic Card" }, { "title": "List" }, { "title": "Carousel" }, { "title": "Browsing Carousel" } ] } } } ] }
Hướng dẫn
Phản hồi của bạn phải bao gồm mediaResponse
với mediaType
là AUDIO
và chứa mediaObject
trong mảng mục của phản hồi nhiều định dạng. Phản hồi nội dung đa phương tiện hỗ trợ một đối tượng nội dung đa phương tiện duy nhất. Đối tượng nội dung đa phương tiện phải bao gồm URL nội dung của tệp âm thanh. Đối tượng nội dung đa phương tiện có thể tuỳ ý bao gồm tên, văn bản phụ (nội dung mô tả) và biểu tượng hoặc URL hình ảnh.
Trên điện thoại và Google Home, khi Hành động của bạn phát xong âm thanh, Trợ lý Google sẽ kiểm tra xem phản hồi của nội dung nghe nhìn có phải là FinalResponse
hay không.
Nếu không, trình này sẽ gửi một lệnh gọi lại đến phương thức thực hiện của bạn để bạn có thể phản hồi người dùng.
Hành động của bạn phải bao gồm khối đề xuất nếu phản hồi không phải là FinalResponse
.
Xử lý lệnh gọi lại sau khi phát xong
Hành động của bạn phải xử lý ý định actions.intent.MEDIA_STATUS
để nhắc người dùng theo dõi (ví dụ: phát một bài hát khác). Hành động của bạn sẽ nhận được lệnh gọi lại này sau khi phát xong nội dung đa phương tiện. Trong lệnh gọi lại, đối số MEDIA_STATUS
chứa thông tin trạng thái của nội dung đa phương tiện hiện tại. Giá trị trạng thái sẽ là FINISHED
hoặc STATUS_UNSPECIFIED
.
Sử dụng Dialogflow
Nếu muốn thực hiện việc phân nhánh trò chuyện trong Dialogflow, bạn cần thiết lập ngữ cảnh đầu vào là actions_capability_media_response_audio
trên ý định để đảm bảo ý định chỉ kích hoạt trên các nền tảng hỗ trợ phản hồi nội dung nghe nhìn.
Xây dựng phương thức thực hiện đơn hàng
Đoạn mã dưới đây cho thấy cách bạn có thể viết mã thực hiện cho Hành động của mình. Nếu bạn đang sử dụng Dialogflow, hãy thay thế actions.intent.MEDIA_STATUS
bằng tên hành động được chỉ định trong ý định nhận sự kiện actions_intent_MEDIA_STATUS
(ví dụ: "media.status.update").
Node.js
app.intent('Media Status', (conv) => { const mediaStatus = conv.arguments.get('MEDIA_STATUS'); let response = 'Unknown media status received.'; if (mediaStatus && mediaStatus.status === 'FINISHED') { response = 'Hope you enjoyed the tune!'; } conv.ask(response); conv.ask('Which response would you like to see next?'); });
Java
@ForIntent("Media Status") public ActionResponse mediaStatus(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); String mediaStatus = request.getMediaStatus(); String response = "Unknown media status received."; if (mediaStatus != null && mediaStatus.equals("FINISHED")) { response = "Hope you enjoyed the tune!"; } responseBuilder.add(response); responseBuilder.add("Which response would you like to see next?"); return responseBuilder.build(); }
Node.js
app.intent('actions.intent.MEDIA_STATUS', (conv) => { const mediaStatus = conv.arguments.get('MEDIA_STATUS'); let response = 'Unknown media status received.'; if (mediaStatus && mediaStatus.status === 'FINISHED') { response = 'Hope you enjoyed the tune!'; } conv.ask(response); conv.ask('Which response would you like to see next?'); });
Java
@ForIntent("actions.intent.MEDIA_STATUS") public ActionResponse mediaStatus(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); String mediaStatus = request.getMediaStatus(); String response = "Unknown media status received."; if (mediaStatus != null && mediaStatus.equals("FINISHED")) { response = "Hope you enjoyed the tune!"; } responseBuilder.add(response); responseBuilder.add("Which response would you like to see next?"); return responseBuilder.build(); }
JSON
Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu webhook.
{ "responseId": "151b68df-98de-41fb-94b5-caeace90a7e9-21947381", "queryResult": { "queryText": "actions_intent_MEDIA_STATUS", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "Webhook failed for intent: Media Status", "fulfillmentMessages": [ { "text": { "text": [ "Webhook failed for intent: Media Status" ] } } ], "outputContexts": [ { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_media_response_audio" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_account_linking" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_web_browser" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_screen_output" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_capability_audio_output" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/google_assistant_input_type_voice" }, { "name": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA/contexts/actions_intent_media_status", "parameters": { "MEDIA_STATUS": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } } ], "intent": { "name": "projects/df-responses-kohler/agent/intents/068b27d3-c148-4044-bfab-dfa37eebd90d", "displayName": "Media Status" }, "intentDetectionConfidence": 1, "languageCode": "en" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "user": { "locale": "en-US", "lastSeen": "2019-08-04T23:57:15Z", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA", "type": "ACTIVE", "conversationToken": "[]" }, "inputs": [ { "intent": "actions.intent.MEDIA_STATUS", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "MEDIA_STATUS", "extension": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] }, "isInSandbox": true, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" } ] } ], "requestType": "SIMULATOR" } }, "session": "projects/df-responses-kohler/agent/sessions/ABwppHHsebncupHK11oKhsCTgyH96GRNYH-xpeeMTqb-cvOxbd67QenbRlZM4bGAIB8_KXdTfI7-7lYVKN1ovAhCaA" }
JSON
Xin lưu ý rằng JSON ở bên dưới mô tả một yêu cầu webhook.
{ "user": { "locale": "en-US", "lastSeen": "2019-08-06T07:38:40Z", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHGcqunXh1M6IE0lu2sVqXdpJfdpC5FWMkMSXQskK1nzb4IkSUSRqQzoEr0Ly0z_G3mwyZlk5rFtd1w", "type": "NEW" }, "inputs": [ { "intent": "actions.intent.MEDIA_STATUS", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "MEDIA_STATUS", "extension": { "@type": "type.googleapis.com/google.actions.v2.MediaStatus", "status": "FINISHED" } } ] } ], "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" } ] }, "isInSandbox": true, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" } ] } ], "requestType": "SIMULATOR" }
Thẻ bảng
Thẻ bảng cho phép bạn hiển thị dữ liệu dạng bảng trong câu trả lời của mình (ví dụ: bảng xếp hạng thể thao, kết quả bầu cử và chuyến bay). Bạn có thể xác định các cột và hàng (tối đa 3 hàng) mà Trợ lý phải hiển thị trong thẻ bảng. Bạn cũng có thể xác định các cột và hàng bổ sung cùng với mức độ ưu tiên của các cột và hàng này.
Bảng khác với danh sách dọc vì bảng hiển thị dữ liệu tĩnh và không tương tác được, chẳng hạn như các phần tử trong danh sách.
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/smart-display/table.png?authuser=7&hl=vi)
Thuộc tính
Thẻ bảng có các yêu cầu và thuộc tính không bắt buộc sau đây mà bạn có thể định cấu hình:
- Được hỗ trợ trên các nền tảng có tính năng
actions.capability.SCREEN_OUTPUT
.
Phần sau đây tóm tắt cách bạn có thể tuỳ chỉnh các phần tử trong thẻ bảng.
Tên | Không bắt buộc | Có thể tuỳ chỉnh | Ghi chú tuỳ chỉnh |
---|---|---|---|
title |
Có | Có | Tiêu đề chung của bảng. Phải đặt nếu đã đặt tiêu đề phụ. Bạn có thể tuỳ chỉnh bộ phông chữ và màu sắc. |
subtitle |
Có | Không | Tiêu đề phụ cho bảng. |
image |
Có | Có | Hình ảnh được liên kết với bảng. |
Row |
Không | Có |
Dữ liệu hàng của bảng. Bao gồm một mảng các đối tượng 3 hàng đầu tiên được đảm bảo sẽ hiển thị, nhưng các hàng khác có thể không xuất hiện trên một số khu vực. Vui lòng kiểm tra bằng trình mô phỏng để xem hàng nào xuất hiện cho một nền tảng nhất định. Trên các nền tảng hỗ trợ tính năng |
ColumnProperties |
Có | Có | Tiêu đề và căn chỉnh của một cột. Bao gồm một thuộc tính header (đại diện cho văn bản tiêu đề của một cột) và thuộc tính horizontal_alignment (thuộc loại HorizontalAlignment ). |
Cell |
Không | Có | Mô tả một ô trong hàng. Mỗi ô chứa một chuỗi đại diện cho một giá trị văn bản. Bạn có thể tuỳ chỉnh văn bản trong ô. |
Button |
Có | Có | Một đối tượng nút thường xuất hiện ở cuối thẻ. Mỗi thẻ bảng chỉ được có 1 nút. Bạn có thể tuỳ chỉnh màu nút. |
HorizontalAlignment |
Có | Có | Căn ngang nội dung trong ô. Giá trị có thể là LEADING , CENTER hoặc TRAILING . Nếu chưa chỉ định, nội dung sẽ được căn chỉnh với cạnh trên cùng của ô. |
Mã mẫu
Các đoạn mã sau đây cho biết cách triển khai một thẻ bảng đơn giản:
Node.js
app.intent('Simple Table Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a simple table example.'); conv.ask(new Table({ dividers: true, columns: ['header 1', 'header 2', 'header 3'], rows: [ ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], ], })); conv.ask('Which response would you like to see next?'); });
Java
@ForIntent("Simple Table Card") public ActionResponse simpleTable(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a simple table example.") .add( new TableCard() .setColumnProperties( Arrays.asList( new TableCardColumnProperties().setHeader("header 1"), new TableCardColumnProperties().setHeader("header 2"), new TableCardColumnProperties().setHeader("header 3"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a simple table example.'); conv.ask(new Table({ dividers: true, columns: ['header 1', 'header 2', 'header 3'], rows: [ ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], ], })); conv.ask('Which response would you like to see next?');
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a simple table example.") .add( new TableCard() .setColumnProperties( Arrays.asList( new TableCardColumnProperties().setHeader("header 1"), new TableCardColumnProperties().setHeader("header 2"), new TableCardColumnProperties().setHeader("header 3"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a simple table example." } }, { "tableCard": { "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true } ], "columnProperties": [ { "header": "header 1" }, { "header": "header 2" }, { "header": "header 3" } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a simple table example." } }, { "tableCard": { "columnProperties": [ { "header": "header 1" }, { "header": "header 2" }, { "header": "header 3" } ], "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } }, "possibleIntents": [ { "intent": "actions.intent.TEXT" } ] } ] }
Các đoạn mã sau đây cho biết cách triển khai một thẻ bảng phức tạp:
Node.js
app.intent('Advanced Table Card', (conv) => { if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a table with all the possible fields.'); conv.ask(new Table({ title: 'Table Title', subtitle: 'Table Subtitle', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Alt Text', }), columns: [ { header: 'header 1', align: 'CENTER', }, { header: 'header 2', align: 'LEADING', }, { header: 'header 3', align: 'TRAILING', }, ], rows: [ { cells: ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], dividerAfter: false, }, { cells: ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], dividerAfter: true, }, { cells: ['row 3 item 1', 'row 3 item 2', 'row 3 item 3'], }, ], buttons: new Button({ title: 'Button Text', url: 'https://assistant.google.com', }), })); conv.ask('Which response would you like to see next?'); });
Java
@ForIntent("Advanced Table Card") public ActionResponse advancedTable(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a table with all the possible fields.") .add( new TableCard() .setTitle("Table Title") .setSubtitle("Table Subtitle") .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Alt text")) .setButtons( Arrays.asList( new Button() .setTitle("Button Text") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))) .setColumnProperties( Arrays.asList( new TableCardColumnProperties() .setHeader("header 1") .setHorizontalAlignment("CENTER"), new TableCardColumnProperties() .setHeader("header 2") .setHorizontalAlignment("LEADING"), new TableCardColumnProperties() .setHeader("header 3") .setHorizontalAlignment("TRAILING"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))) .setDividerAfter(false), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3"))) .setDividerAfter(true), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build(); }
Node.js
if (!conv.screen) { conv.ask('Sorry, try this on a screen device or select the ' + 'phone surface in the simulator.'); conv.ask('Which response would you like to see next?'); return; } conv.ask('This is a table with all the possible fields.'); conv.ask(new Table({ title: 'Table Title', subtitle: 'Table Subtitle', image: new Image({ url: 'https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png', alt: 'Alt Text', }), columns: [ { header: 'header 1', align: 'CENTER', }, { header: 'header 2', align: 'LEADING', }, { header: 'header 3', align: 'TRAILING', }, ], rows: [ { cells: ['row 1 item 1', 'row 1 item 2', 'row 1 item 3'], dividerAfter: false, }, { cells: ['row 2 item 1', 'row 2 item 2', 'row 2 item 3'], dividerAfter: true, }, { cells: ['row 3 item 1', 'row 3 item 2', 'row 3 item 3'], }, ], buttons: new Button({ title: 'Button Text', url: 'https://assistant.google.com', }), })); conv.ask('Which response would you like to see next?');
Java
ResponseBuilder responseBuilder = getResponseBuilder(request); if (!request.hasCapability(Capability.SCREEN_OUTPUT.getValue())) { return responseBuilder .add("Sorry, try ths on a screen device or select the phone surface in the simulator.") .add("Which response would you like to see next?") .build(); } responseBuilder .add("This is a table with all the possible fields.") .add( new TableCard() .setTitle("Table Title") .setSubtitle("Table Subtitle") .setImage( new Image() .setUrl( "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png") .setAccessibilityText("Alt text")) .setButtons( Arrays.asList( new Button() .setTitle("Button Text") .setOpenUrlAction( new OpenUrlAction().setUrl("https://assistant.google.com")))) .setColumnProperties( Arrays.asList( new TableCardColumnProperties() .setHeader("header 1") .setHorizontalAlignment("CENTER"), new TableCardColumnProperties() .setHeader("header 2") .setHorizontalAlignment("LEADING"), new TableCardColumnProperties() .setHeader("header 3") .setHorizontalAlignment("TRAILING"))) .setRows( Arrays.asList( new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 1 item 1"), new TableCardCell().setText("row 1 item 2"), new TableCardCell().setText("row 1 item 3"))) .setDividerAfter(false), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3"))) .setDividerAfter(true), new TableCardRow() .setCells( Arrays.asList( new TableCardCell().setText("row 2 item 1"), new TableCardCell().setText("row 2 item 2"), new TableCardCell().setText("row 2 item 3")))))); return responseBuilder.build();
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "This is a table with all the possible fields." } }, { "tableCard": { "title": "Table Title", "subtitle": "Table Subtitle", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Alt Text" }, "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": false }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 3 item 1" }, { "text": "row 3 item 2" }, { "text": "row 3 item 3" } ] } ], "columnProperties": [ { "header": "header 1", "horizontalAlignment": "CENTER" }, { "header": "header 2", "horizontalAlignment": "LEADING" }, { "header": "header 3", "horizontalAlignment": "TRAILING" } ], "buttons": [ { "title": "Button Text", "openUrlAction": { "url": "https://assistant.google.com" } } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } }
JSON
Xin lưu ý rằng JSON dưới đây mô tả phản hồi webhook.
{ "expectUserResponse": true, "expectedInputs": [ { "possibleIntents": [ { "intent": "actions.intent.TEXT" } ], "inputPrompt": { "richInitialPrompt": { "items": [ { "simpleResponse": { "textToSpeech": "This is a table with all the possible fields." } }, { "tableCard": { "title": "Table Title", "subtitle": "Table Subtitle", "image": { "url": "https://storage.googleapis.com/actionsresources/logo_assistant_2x_64dp.png", "accessibilityText": "Alt Text" }, "rows": [ { "cells": [ { "text": "row 1 item 1" }, { "text": "row 1 item 2" }, { "text": "row 1 item 3" } ], "dividerAfter": false }, { "cells": [ { "text": "row 2 item 1" }, { "text": "row 2 item 2" }, { "text": "row 2 item 3" } ], "dividerAfter": true }, { "cells": [ { "text": "row 3 item 1" }, { "text": "row 3 item 2" }, { "text": "row 3 item 3" } ] } ], "columnProperties": [ { "header": "header 1", "horizontalAlignment": "CENTER" }, { "header": "header 2", "horizontalAlignment": "LEADING" }, { "header": "header 3", "horizontalAlignment": "TRAILING" } ], "buttons": [ { "title": "Button Text", "openUrlAction": { "url": "https://assistant.google.com" } } ] } }, { "simpleResponse": { "textToSpeech": "Which response would you like to see next?" } } ] } } } ] }
Tuỳ chỉnh câu trả lời của bạn
Bạn có thể thay đổi giao diện của câu trả lời nhiều định dạng bằng cách tạo một giao diện tuỳ chỉnh. Nếu bạn đã xác định giao diện cho dự án Actions (Hành động), thì phản hồi đa dạng thức trên các Hành động của dự án sẽ được tạo kiểu theo giao diện của bạn. Việc xây dựng thương hiệu tuỳ chỉnh này có thể hữu ích cho việc xác định giao diện độc đáo cho cuộc trò chuyện khi người dùng gọi Hành động của bạn trên một nền tảng có màn hình.
Để đặt giao diện phản hồi tuỳ chỉnh, hãy làm như sau:
- Trong Bảng điều khiển Actions, hãy chuyển đến phần Phát triển > Tuỳ chỉnh giao diện.
- Thiết lập một hoặc tất cả các giá trị sau:
- Màu nền được dùng làm nền cho thẻ của bạn. Nhìn chung, bạn nên sử dụng màu sáng cho nền để nội dung thẻ dễ đọc.
- Màu chính là màu chính cho văn bản tiêu đề và thành phần trên giao diện người dùng của thẻ. Nhìn chung, bạn nên sử dụng màu chính tối hơn để tương phản với nền.
- Bộ phông chữ mô tả loại phông chữ dùng cho tiêu đề và các thành phần văn bản nổi bật khác.
- Kiểu góc của hình ảnh có thể thay đổi giao diện của các góc của thẻ.
- Hình nền sử dụng hình ảnh tuỳ chỉnh thay cho màu nền. Bạn cần cung cấp 2 hình ảnh riêng biệt khi thiết bị bề mặt ở chế độ ngang hoặc dọc tương ứng. Lưu ý rằng nếu bạn sử dụng hình nền, màu chính sẽ được đặt thành màu trắng.
- Nhấp vào Lưu.
![](https://developers-dot-devsite-v2-prod.appspot.com/static/assistant/conversational/images/theme-customization.png?authuser=7&hl=vi)