As users interact with Bixby, it communicates back to them in various ways. This could be as simple as the result of a user utterance, or it could be a request for additional information. These messages, or dialog, tell users what is happening, what has happened, and what can happen next.
A typical interaction might start with a user asking "What's the weather like in Palo Alto, California this Friday?" After Bixby processes this request, the user sees this sequence of messages:
Checking the weather...
Here's the weather on Friday for Palo Alto, CA
Bixby dynamically generates messages to communicate with the user. These messages complement Bixby Views by giving status information, paraphrasing results, asking questions, and much more. Bixby provides some default messages for results, but you might want to add your own custom messages to truly match the tone and approach of your capsule. You can improve these messages by writing custom dialog files.
If Bixby is being used on a device with a screen, the dialog appears in the conversation zone of that screen.
You should wait until your models are fully formed before working on dialog.
In its simplest form, a dialog file looks like this:
dialog (Concept) {
match: NumDice
template ("Number of dice")
}
The template begins by specifying a Dialog Mode. Then it specifies a match pattern and a template, the actual dialog text.
The dialog mode, match pattern, and control flows determine the single template that should be presented to the user. If more than one dialog
matches based on its match pattern, Bixby will select the most specific one.
Template strings can contain Expression Language to create dynamic content. Expression Language lets you compose the message using formatting functions and invoke other dialog. If you do not want to show any message, or you would like to remove a default Bixby message, you can use an empty template template()
.
You should start by defining dialog for simple match patterns and use them as building blocks for more complex ones. You can use the match pattern to bind values for use in the dialog template. Dialogs support simple conditional logic and template substitution. You can even use a switch
with Expression Language functions such as plural
, state
, and size
.
Dialog shows up in different situations based on the mode, which can fall into two major categories: events and fragments.
Events describe how to notify the user about something that has happened or needs to happen. For example, one of the most common events is a result. Here's an example dialog for the results of the example.movieAgent
capsule:
dialog (Result) {
match: Movie (movie) {
from-output: FindMovie (action)
}
macro (MOVIE_RESULT) {
param (movie) {
expression (movie)
}
param (action) {
expression (action)
}
}
}
Notice that this dialog uses a template macro
, which allows you to reuse dialog in several places. Here is the macro-def
that defines the macro
:
macro-def (MOVIE_RESULT) {
params {
param (movie) {
type (Movie)
min (Optional)
max (Many)
}
param (action) {
type (FindMovie)
min (Optional)
max (One)
}
param (fromQuiz) {
type (core.Boolean)
min (Optional)
max (One)
default (false)
}
}
content {
if (size(movie) == 1) {
if ($handsFree) {
template ("[#{value(movie.movieDetails.overview)}] I hope you enjoy #{macro('MOVIE_VALUE', movie)}!")
}
else {
template ("Here's a #{macro('MOVIE_FROM_FINDMOVIE_CONCEPT', movie, action)}.")
}
}
else {
if (fromQuiz) {
template ("Based on your answers, I found some [#{lower(macro('MOVIE_GENRE_VALUE', action.genre))}] movies perfect for you.")
}
else {
template ("Here are a few #{macro('MOVIE_FROM_FINDMOVIE_CONCEPT', movie, action)}.")
}
}
}
}
As compared to events, fragments form the building blocks of an event. They determine how to format concepts and actions within an event message.
There can be multiple dialog fragments that make up a specific dialog event.
When customizing a dialog event, keep variable dialog in dialog fragments. You should define dialog incrementally, starting with the simplest modes, and use them as building blocks for the more complex ones: Concept
, Value
, Input
, Action
, Progress
, NoResult
, Result
.
Make sure any text you write for Bixby follows the dialog best practices as well as the Writing Dialog Design Guide.
Keep in mind that, by default, Bixby provides default dialog for your capsule. However, you will likely find cases where it seems awkward or even ungrammatical. For example, suppose we send this input structure to a flight search action:
// Find the best seats on a United Airbus 319 plane
example.air.AirplaneSeatDetails {
example.air.CarrierName (United Airlines, Inc.)
example.air.AirplaneModelName ("Airbus 319 (319)")
example.rating.Score (5)
}
Here is the Progress event dialog:
Getting airplane seat details where the airplane model name is Airbus 319 (319), where the carrier name is United Airlines, Inc., and where the score is 5.0...
This is the Result event dialog:
Here are 10 airplane seat details where the airplane model name is Airbus 319 (319), where the carrier name is United Airlines, Inc., and where the score is 5.0:
We can make this sound more natural by changing "airplane seat details" to "seat descriptions" by defining a custom dialog:
Open the File menu and select New File.
Choose Dialog in the Type menu.
Provide a name for the file.
Select Create.
Enter code similar to the following:
dialog (Concept) {
match: example.air.AirplaneSeatDetails (this)
switch (plural(this)) {
case (One) {
template (seat description)
}
default {
template (seat descriptions)
}
}
}
Now the above query produces a better dialog:
Getting seat descriptions where the airplane model name is...
You can use execution states to adjust a verb phrase based on the status of an action.
The available execution states for dialog are as follows:
Pre
: dialog before an action occursMid
: dialog while an action is occurringPost
: dialog after an action occursFor example, if a user is buying event tickets, here is an example action dialog that has execution states covering stages of the transaction:
dialog (Action) {
match {
example.ticketbuying.Pay (action)
}
switch (state(action)) {
case (Pre) {
template ("buy tickets")
}
case (Mid) {
template ("completing your purchase")
}
case (Post) {
template ("processed payment")
}
}
}
The execution state will be fully settled before any dialogs are requested and resolved.
Concept features determine whether a concept refers to one, many, or is location-specific.
The available features for dialog are as follows:
Definite
: a concept referring to single cardinalityIndefinite
: a concept referring to a multiple cardinality (group)Proximal
: a concept referring to a locationFor an example of Definite
and Indefinite
, here is a concept fragment
representing either Definite or Indefinite cardinality for movie properties such
as genre or release date:
dialog (Concept) {
match: _ (this) {
from-property: movie.Movie (source)
}
template ("#{concept (this)} of #{size(source) == 1 ? concept (source, 'Definite') : concept (source, 'Indefinite')}")
}
When size is one, the output would read director of the movie. Otherwise, Bixby says directors of a movie.
In this dialog event, which uses Proximal
, the user is asked to select a
specific point of interest:
dialog (Selection) {
match {
geo.PointOfInterest (this) {
from-output: geo.FindPointOfInterest (action)
}
}
choose (First) {
if (exists(action.name)) {
template("Which #{value (action.name)}?")
} else {
template("Which one of #{concept (this, 'Proximal')}?")
}
}
}
If the first template is chosen, Bixby might say something like Which Bay Bridge?. Otherwise, it would say Which one of these Bay Bridges?
Bixby generates events before, during, and after execution, and displays some of these events to the user through dialogs. We call these dialog events. When presenting an event, Bixby tries to form complete sentences that fully describe the surrounding context.
To create a new dialog event template, start by identifying the event mode you need. Run your utterance in the Simulator, and you can see the dialog events that each dialog triggers. In the Inspector of the Debug Console, you can expand the Dialog section. Click the dialog you want to inspect, and it will tell you which mode
is being used to trigger that dialog.
Some of the most common dialog events are the following:
Result
: inform the user about results in a succinct way.dialog (Result) {
match {
Shoe(this)
}
template ("I found #{spell (size(this))} #{concept(this)}:")
}
NoResult
: inform the user that no result is available.dialog (NoResult) {
match: Content
template("Nothing found")
}
Progress
: inform the user about an ongoing action.dialog (Progress) {
match: Earthquake (earthquake)
template("Checking for earthquakes based on your search criteria...")
}
Selection
: prompt the user to make a choice from results.
dialog (Selection) {
match {
example.florist.Occasion
}
template("What's the occasion?")
}
You can read more about dialog events and see a list of them in reference documentation.
Whenever Bixby generates dialog, it refers to concepts and actions and renders dialogs using dialog fragments.
The dialog fragment modes are as follows:
Action
: A verb phrase describing action state.Concept
: A descriptive noun phrase for one or more concept values.Input
: An action input required for one or more concept value.Value
: The canonical representation of one or more concept values.Structure
: A Value
fragment for structures.To provide a minimal level of dialog for capsules, Bixby includes a number of default dialog fragment templates that cover common cases.
You can read more about and see a list of dialog fragments in reference documentation.
Dialog fragments are independent of Dialog Events. Fragments are never invoked on their own, but are used as building blocks inside dialogs that are triggered by events.
If you have fragments that are optional, you can put them in square brackets ([]
). If a section of a template within these brackets fails to render, that section will be skipped.
template ("[#{lower(macro('MOVIE_GENRE_VALUE', action.genre))}] movie[ released #{macro('RELEASE_DATE_TIME_EXPRESSION_VALUE', action.releaseDateTimeExpression)}][ with #{value(action.person.name)}]")
Dialogs are built recursively by invoking the dialogs for Events and Fragments inside. To understand the inner composition of these dialogs, you can always take a look in the Debug Console. Specifically, you can take a look at the X-Ray Pane to discover which concepts and their values are being called and from which file.
If you are combining different parts of the dialog into a single output, you might want to change the order of those parts. In order to do this, you will need to find the parent of the parts and change the order there.
For example, let's say Bixby has a NoResult
event that says "I can't find any business" and an Input fragment that says "where the city is Beijing". Combined, Bixby might say "I can't find any business where the city is Beijing". To switch the order of this, you would find the parent of both the event and the input fragment (in this case, No Result for Business) and change the order there, like in the following example:
dialog (NoResult) {
match: yourNamespace.YourBusiness (output) {
from-output: yourNamespace.YourFindBusiness (action)
}
template("[#{joinAs('input', action.city, action.keyword)} ] I can't find any #{concept(output.without(action))}")
}
This would produce I can't find any in Beijing and I can't find any business.
There might be situations where you don't want dialog to appear. In this case, you can use an empty dialog template (template( )
).
Dialog is often both presented visually on a Bixby device screen and spoken aloud by Bixby's text-to-speech (TTS) engine. It's possible to tune the text-to-speech by using the speech
child key of template
. In this example, "Copernicus AMS" has a speech
key that separates the letters A M S
to force Bixby to speak the letters separately rather than pronouncing them as the word "ams":
dialog (Result) {
match: AirQuality (this) {
from-output: GetAirQuality (action)
}
template ("Current air quality is #{lower (category)} with an index of #{value (index)}, according to Copernicus AMS.") {
speech ("Current air quality is #{lower (category)} with an index of #{value (index)}, according to Copernicus A M S.")
}
}
Dialogue in speech
can also use a subset of Speech Synthesis Markup Language (SSML) for further tuning. See Using SSML for more information on Bixby's SSML support.
Some languages have different inflected forms of their words based on the gender and plurality of the term to which they are linked. Since these terms can be filled in at runtime through templates (like with #{concept(this)}
), Bixby supports a special syntax for handling agreement of gender and case within dialog templates.
Nouns should be bracketed with %{id:noun}
, where id
can be any number:
%{1:chose}
These are used to match against agreement expressions of the form @{id<type>:val1,val2}
:
@{1g:le,la}
id
is the number of the term that this expression should be matched against;<type>
is a locale-specific letter code indicating the kind of agreement being evaluated, in this case g
for gender (c
for case would also be common);val
, val2
, etc., are the values for each gender or case, in a locale-specific order. These values can be the empty string.Take the following example template:
template("Et voilà @{1g:le,la} %{1:#{concept(this)}} trouvé@{1g:,e}")
Template expressions are evaluated first; if concept(this)
evaluated to chose
("thing" in French), the template string would now be as follows:
Et voilà @{1g:le,la} %{1:chose} trouvé@{1g:,e}}
Now, the agreement expressions would be processed. The gender of chose (female) would be determined by Bixby and the correct values would be substituted in:
Et voilà la chose trouvée
The letter codes for agreement type and the orders are locale-specific. In addition, some locales might execute a final post-processing step that adjusts spelling based on context (such as changing "ce ingrédient" to "cet ingrédient").
Currently, the only language Bixby has agreement processing rules for in templates is French:
g
for gender agreement@{1g:le,la}
If you are developing a capsule for multiple experiences, such as hands-eyes free or for various devices, keep in mind that you might have to use different dialogs. This is definitely true if you are developing for multiple locales. In order to minimize the work you have to do, we recommend that you take advantage of dialog macros like you would when localizing your capsule. See the Design Guides and Dialog Best Practices for more guidance on writing dialog for these different experiences.