Bixby Developer Center

Space Resorts Sample Capsule

The example.spaceResorts sample capsule demonstrates a fully-developed capsule that uses several of the features and abilities discussed in the Developers' Guides, while also using the best practices described in the Design Guides.

Additional and more in-depth information on the example.spaceResorts sample capsule can be found in the videos section.

Note

Because you cannot submit a capsule with the example namespace, in order to test a sample capsule on a device, you must change the id in the capsule.bxb file from example to your organization's namespace before making a private submission.

For example, if your namespace is acme, change example.spaceResorts to acme.spaceResorts.

Download this Capsule

About Space Resorts

Before you start developing a capsule, your first step is to properly plan your capsule. This means identifying the purpose of your capsule and listing use cases by identifying the utterances users might say.

The example.spaceResorts capsule's main purpose is to find and book a fictional space resort vacation. You can run the sample capsule in the Simulator with the trained utterances provided in the capsule. We provide several example user utterances in the README file. The utterances are grouped by the conversation flow and by utterance type. For example, if users are simply browsing available resorts, they would be in the Find Flow and might ask something like "Search for hotels around The Red Planet". To improve the search results in that flow, a continuation utterance might be "Only the ones that are kid friendly".

There are two main conversation flows in this capsule:

  • A find flow, which focuses on searching for a specific space resort based on a user's request. This is similar to the simple search sample capsule walkthrough:

    1. Users request to find a space resort, based on some criteria they have in mind or just in general.
    2. Bixby returns a list of space resorts that match the user request.
    3. If users want more details, they select a space resort for more information.

  • A book flow, which focuses on a transactional workflow to book a chosen resort. This is similar to the basic cart sample capsule walkthrough. Note that this flow requires using the find flow:

    1. Users initialize the transaction by searching for a space resort that meets their need.
    2. Users change or update the order that Bixby creates, providing any information that Bixby needs when asked.
    3. Bixby presents the order to finalize the details, letting users confirm or cancel the order.
    4. Bixby prints a receipt for users, which they can use to look up any information about the order they made and check the status of that order.

Once you've had the chance to play around with the sample capsule, this guide will give a brief overview of the various parts that make up this capsule and provide resources for implementation details.

You should also take a look at the debug console, to help you understand the programs that Bixby generates and how various views, concepts, actions, layouts, and dialogs are called throughout the execution.

Models

At the core of every capsule is modeling, as explained in the Quick Start Guide and Introduction to Modeling. You need to identify what your capsule is doing (actions) and what parts are accomplishing these things (concepts).

For example, if a user wants to look at the different options available, Bixby will need some sort of Search action to look through available Space Resorts. Within this action, you need to consider the different parameters a user might ask for (such as various planets or additional SearchCriteria), as well as the actual output from the Search action (in this case, a SpaceResort structure). As with other capsules, models in this capsule are divided by Concepts and Actions. This section gives a brief overview of each.

Space Resort Concepts

Concept models are used as the objects that actions are applied to. It might be useful to look at the objects being returned from your API to determine which properties your complex structures need to be mapped to, as well as which primitives need to be created. For example, the SpaceResort structure matches its properties to the various properties returned from each object in the spaceResorts.js JSON file.

Here is an example JSON space resort object:

    {
name: loc(names.Mercurial),
planet: planets.Mercury,
gravity: 0.38,
description: loc(descriptions.Mercurial),
amenities: [loc(amenities.CraterCanyoneering), loc(amenities.PetFriendly), loc(amenities.RoverRentals)],
highlight: loc(highlights.Mercurial),
images: images.Mercurial,
all: true
},

View 8fa06f8 on GitHub

Note

The loc function in name is returning the localized version of the string for that field, based on the user's language.

This is the corresponding SpaceResort structure model:

structure (SpaceResort) {
description (Space resort)
property (name) {
min (Required)
type (Name)
}
property (description) {
min (Required)
type (Description)
}
property (attributes) {
type (Attributes)
min (Required)
max (Many)
}
property (planet) {
min (Required)
type (Planet)
}
property (gravity) {
min (Required)
type (Gravity)
}
property (highlight) {
type (Highlight)
}
property (images) {
type (Image)
max (Many)
}
property (all) {
description (Training goal for generic find space resort queries)
type (ViewAll)
min (Required) max (One)
}
features {
// Using preference learning to observe which planets the user tends to select and then provide personalized highlights based on these
preferable {
preference (planet)
}
}

}

View master on GitHub

The example.spaceResorts concepts are sorted by primitives and structures, which is a useful way to separate your more complex structures with their simpler building blocks. The primitives and structures folders are further separated by the flow that they're primarily used for: find and book. Several of the primitive models have explanations on why the type was chosen. For example, the Planet model is an enum because there are only a finite and definitive list of planets.

Note

Because the find flow is used within the book flow, several of the concepts defined in the find folder are also used during the book flow.

The structures use several useful features such as role-of, features, and named-consumer. For example, the Item structure is tagged with features { transient } to indicate to Bixby that the given pod reservation should not be tracked across execution states. Another example is that the Buyer model uses role-of (self.Profile). Importing an existing capsule (in this case, viv.self), especially one of the library capsules, allows you to create structures in your own capsule without having to recreate commonly used objects.

For more information on how to model concepts, see Modeling Concepts.

Space Resort Actions

The space resorts actions handles two main conversational flows from a user, as stated before: find and book. This section briefly discusses the action models to support these conversational flows.

Find a Space Resort

The find conversation flow relies on a single action model, FindSpaceResorts .The FindSpaceResorts action is of type Search, with its output being a SpaceResort structure.

This action uses error handling. The first error notifies users when they search for a space resort using criteria that is not supported. This pauses execution and reports to the user Unsupported search criteria with the UnsupportedSearchOption template macro. The second error handles all unknown errors, indicating to the user Something's wrong.

The FindSpaceResorts action looks through the list of available space resorts in the code/find/spaceResorts.js file and returns the ones that fit the user request. To format these results, use a result-view, which you can read more about in the Views section.

You can read about a similar flow in the example.shoe sample capsule walkthrough.

Book a Space Resort

The book conversation flow is a little more complex. It is a transaction workflow that asks users to pick a resort and to input some reservation information. Bixby then creates a simulated hold on a space pod at one of the resorts. Users can check on their reservation and make changes to their order, as well.

This sample capsule separates the action models for booking into two categories: helpers and user-goals.

The helper actions assist in achieving the goals for each user-goals action. For example, the ConstructDateIntervalFromDateTimeExpression takes a dateTimeExpression and converts it into a DateInterval that can be used in the GetDateInterval action. Notice that these helper functions would never be called by Bixby directly.

The user-goals actions aim to complete a goal for a user. For example, if a user asks "Book a honeymoon suite at Triton Water Park for December 25-27", then the goal is Order. Bixby then uses CreateOrder to manufacture an order. If that user decides to follow up that request with an utterance like "Make that between January 3-15", Bixby needs to update the order and uses the UpdateOrder action model.

You can read a similar conversation pattern and implementation details in the example.shirt sample capsule walkthrough. For more information on transactions, see the Transactional Workflows Developers' Guide.

Actions and Endpoints

While Bixby can generate a program with your models and concepts, you need to either implement your own JavaScript or call on an API to help Bixby execute this program. Your actions should have the same inputs and output as the APIs you're calling. (This is similar to making your structures' properties match the properties of your returned JSON objects.) You should also ensure that the accepted-inputs listed in your endpoints file match your actions and APIs. You can read more about Calling APIs in Actions Developers' Guide.

For example.spaceResorts, local JavaScript files include all the necessary action implementations for each of the actions modeled, even sorting the various *.js files the same way as the action models. JavaScript in this capsule is executed in the cloud through Bixby servers, though JavaScript can also be executed on your server if your capsule uses remote endpoints. Additionally, the objects being returned from the calls are also in local JSON files, under the code/lib directory.

Notice that this capsule separates the endpoints depending on the conversation: find.endpoints.bxb and book.endpoints.bxb. While it is not necessary to separate them out, it makes it easier to functionally sort and distinguish between the two. For both files, while some of the actions specify accepted-inputs, all of them use local-endpoints.

Also note that the capsule.properties file sets several configuration properties that are used in the JavaScript files. The getLocalizedRelevantHours() function then calls these properties, depending on the locale, using the config.get() JavaScript method provided by the platform. The JavaScript API provides several useful methods for you to use, such as processing Date/Time and using OAuth Calls.

Views

After the basis of the capsule has been laid and your models are solid, you can add the visible user interface layers: views. While the platform does provide a basic look-and-feel, you should build your own views, and add corresponding layouts or macros to fully customize your capsule.

Pay particular attention to what type of Moment you're designing for with each View. Notice that example.spaceResorts separates the layouts by the type of content being displayed. Specifically, it organizes the layouts by which information is either being asked for or displayed at time, meaning it is organized by which Moment the user is in.

For example, when Bixby needs to know which type of room the user wants for their reservation, this is an Input Moment. Specifically, Bixby looks to the HabitatPod folder, which holds the Input.view.bxb file that displays the options. Additionally, the Summary.macro.bxb file defines what information each HabitatPod displays in the input view. There is a different input view for each type of information that Bixby needs from the user, which follows the design guidelines. This is to ensure that the user is never overwhelmed during a particular moment. Further, this enables you to support this capsule in hands-free mode.

Similarly, during the Confirmation Moment, when Bixby asks the user "_Are you sure you want to book this trip?, the confirmation view is also shown, summarizing the reservation details and includes the following information using layout macros:

  • order-image-card: An image card with a high level summary of information.
  • order-details: A more detailed amount of information listed, using a combination of components.
  • order-contact-information: A separate section listing the contact information of the person staying at the resort. The default generated information is pulled from the viv.self library capsule.

Notice that this confirmation view has components that are tappable and editable, because you need to give the user an option to edit any of the choices they made, in case they change their mind.

The result views can be used in many ways. If a user is doing a transaction, your result-view needs to be a receipt, but if a user is simply browsing through options, providing choices or providing details is sufficient. Which result view gets invoked depends on the match-pattern and on which resource folder matches the current device type and language.

The result views for bixby-mobile are defined in resources/bixby-mobile/layouts. These feature-rich layouts adapt to the number of results returned. If there's a single result, the details of that specific resort are outputted:

    if (size(result) == 1) {
layout {
macro (space-resort-details) {
param (spaceResort) {
expression (result)
}
}

View 1e25bcd on GitHub

Otherwise, the resorts are presented as a list of summary items with highlighted options:

result-view {
// This view handles the Find flow space resort results. For example: "Find space resorts around Jupiter."
// These are trained as a property projection to the `SpaceResort#all` property to indicate that we want to present the entire space resort information (see the README for more details about this annotation pattern)
// We use the following match pattern to identify results with that goal, then we render the space resort result(s) accordingly in the `render` block
match {
ViewAll(all) {
from-property {
SpaceResort (result) {
min (Required)
}
}
}
}

message {
macro (SPACE_RESORT_RESULT) {
param (result) {expression (result)}
}
}

render {
if (size(result) > 1) {
// When there are multiple space resorts, we present them in a list of summary items
list-of (result) {
where-each (item) {
macro (space-resort-summary) {
param (spaceResort) {
expression(item)
}
}
}
// We highlight a few top results for the user with a more prominent layout
highlights {
select(pick) {
// This first highlight uses preference learning to present a personalized recommendation based on the user's past behavior
label {
macro (HIGHLIGHT_LABEL_BY_PREFERENCES)
}
macro (space-resort-highlight) {
param (spaceResort) {
expression(pick)
}
}
order-by {
sorting (pick) {
by-preferences
}
}
}
select(pick) {
label("#{raw(pick.highlight)}")
macro (space-resort-highlight) {
param (spaceResort) {
expression(pick)
}
}
filter-by (exists(pick.highlight))
}
select(pick) {
label("#{raw(pick.highlight)}")
macro (space-resort-highlight) {
param (spaceResort) {
expression(pick)
}
}
filter-by (exists(pick.highlight))
}
select(pick) {
label("#{raw(pick.highlight)}")
macro (space-resort-highlight) {
param (spaceResort) {
expression(pick)
}
}
filter-by (exists(pick.highlight))
}
}
}
} else-if (size(result) == 1) {
// When there is a single result, we directly display the details layout with all the space resort information
layout {
macro (space-resort-details) {
param (spaceResort) {
expression (result)
}
}
}
}
}

conversation-drivers {
if ("size(result) == 1") {
conversation-driver {
macro (MakeReservation)
}
}
}
}

View master on GitHub

There is also a conversation-driver when there is one result being displayed. This encourages users to continue engaging with Bixby, even after this conversation flow could potentially be over. In this case, it asks users if they'd like to make a reservation to that resort.

For more information on creating UI for specific moments, see the Building Bixby Views Developers' Guide. For guidance on what to put in each View, see the Designing Conversations Design Guide.

Training

In order for a capsule to be at full capability, you need to train it for each locale you plan to support. With example.spaceResort, the targets listed in the capsule.bxb file indicate that US English and South Korean Korean are supported for mobile devices:

    targets {
target (bixby-mobile-en-US)
target (bixby-mobile-ko-KR)
}

View 698bec2 on GitHub

That means each locale in the resources folder needs its own training file.

In addition to training, each locale has a supported vocab folder with three separate vocabulary files. Vocabulary helps Bixby understand variations of utterances that you've trained. The vocab files cover these types of phrases in each language:

  • Confirmation - Ways for the user to indicate whether they approve or disapprove of a choice.
  • Planet - Other names or nicknames of the planets.
  • SearchCriteria - Various phrases that can be used as search criteria while finding a space resort.

Dialogs

Dialog is the primary way Bixby talks to the user, by asking questions, responding with answers, or providing feedback.

The base dialog files handle the various situations in which dialog might be called, depending on the match pattern used. For example, if Bixby is asking for a DateInterval, this is an Elicitation dialog event. As such, Bixby calls the DateInterval/Elicitation.macro.bxb file, which invokes the WhenDoYouWantToStay template macro. This template macro asks the user When do you want to stay?.

You should build out your dialogs, starting with useful dialog fragments and then building them up to more complicated situations. For example, there is a SpaceResort concept fragment that handles the difference between a singular or plural instance:

dialog (Concept) {
match: SpaceResort (this)
switch (plural(this)) {
case (One) {
template (space resort)
}
default {
template (space resorts)
}
}
}

View master on GitHub

You can also extract dialog into template macros by defining them in a macro-def, which can in turn call other template macros and dialog fragments. You can even use conditionals to present different dialogs depending on dynamic properties using Expression Language.

Notice that example.spaceResorts is available both in English and Korean as indicated in the training section. This means this capsule has been localized for users in the US and South Korea. It accomplishes this mostly by using separate template macros for various things:

  • nlg-strings.macro.bxb - Handles dialog spoken by Bixby.
  • ui-strings.macro.bxb - Handles labels and various preface text shown on the UI.

This reduces your need to replicate dialog files across locale folders, as the base folder handles several of these situations and knows how to call the correct dialog string based on the locale Bixby is being used in. You might have to rewrite some of the dialog files, depending on the grammar of the locale, which is explained further in the Trade Offs of Fragmentation section. For more information on how to localize your docs, see the localization topic.

For more information on writing your dialog, see the Refining Dialog Developers' Guide and the Writing Dialog Design Guide.

Libraries and Permissions

The example.spaceResorts capsule is also a good example of importing libraries and requesting permissions from users. It imports the viv.self library and several other libraries to help with modeling:

    capsule-imports {
import (viv.core) {
as (core)
}
import (viv.self) {
as (self)
version (4.0.25)
}
import (viv.time) {
as (time)
version-from (self)
}
import (viv.money) {
as (money)
version (2.22.56)
}
}

View 698bec2 on GitHub

For more information on existing libraries you can import, see the Library Capsules Reference.

Additionally, you can request the self:profile permission because of the imported viv.self, also in the capsule.bxb file:

    permissions {
library-permission (self:profile)
// Note: While this permission is declared, it is not being used and the user will not be prompted, because we are fetching an 'imaginary' mocked profile from viv.self.
// This is done by passing an 'imaginary' flag to the self.GetProfile action, which we do on line 17 of models/actions/book/user-goals/CreateOrder.model.bxb: `value: self.Imaginary(true)`
// Commenting out that line will cause viv.self to fetch the user's profile instead of a mocked profile, and the user will be prompted for this 'profile' permission when viv.self tries to fetch it.
}

View 698bec2 on GitHub

The capsule-info.bxb file contains the justification on why you're requesting this permission from users:

  requested-permissions {
permission (self:profile){
justification (Your profile information is needed to book a space resort.)
}
}

View 859fd99 on GitHub

Notice that this capsule is not actively using the self:profile permission because in the models/actions/book/user-goals/CreateOrder.model.bxb action model, the default-init initializes an "imaginary" profile provided in the viv.self library by passing self.Imaginary(true) into the value of the intent:

      default-init {
intent {
goal: self.GetProfile
value: self.Imaginary(true)
value-set: self.RequiredField {
self.RequiredField(firstName)
self.RequiredField(lastName)
self.RequiredField(emailInfo)
self.RequiredField(phoneInfo)
}
}
}
}

View 4a622af on GitHub

If you comment out line 17 from models/actions/book/user-goals/CreateOrder.model.bxb, then when you run Space Resorts in the Simulator, you will get prompted to grant permissions. For more information about how permissions work, see Grant Capsule Permissions.

Stories

Stories enable you to check your code and ensure that the conversation flow matches your capsule design. Repeatedly testing your capsules is generally a good practice. Additionally, you can add assertions to your stories to ensure that certain values, dialogs, layouts, and templates are being properly called.

The example.spaceResorts includes two stories for the English locale, one for each conversation flow: booking and find. The booking reservation tests making a reservation for a space resort that is good for kids, further testing a user tapping on several options presented. The find story simply tests the "find space resorts" utterance and branches off on several continuations to that utterance.

For more information on testing your capsule, including how to debug any issues, see the Testing Capsules Developers' Guide.