I want to make Bixby ask for input values when the user just states what he/she wants to do(without any valuable input given.)
For example,
user: I want to search something
Bixby: What do you want to search?
user: *possible-input-value*
Is this possible? If so, how can I implement this?
That's easy in Bixby. If you make an input to your action required...it will prompt the user for input. Let's say you have an action like this:
action (FindSomething) {
type(Search)
description (Search for something)
collect {
input (search) {
type (Search)
min (Required) max (One) // Force Bixby to prompt for an input.
}
}
output (viv.core.Text) // some result
}
And you have a search concept defined like this:
name (Search) {
description (Search term)
}
You can provide an input view for the user to enter the term (via screen).
input-view {
match: Search(search)
message {
template ("What do you want to search?")
}
render {
form {
elements {
text-input {
id (search)
label (Search Term)
type (Search)
max-length (50)
value ("#{raw(search)}")
}
}
on-submit {
goal: Search
value: viv.core.FormElement(search)
}
}
}
}
In addition to Pete's response, you need to enable this for voice input (UI only input will not pass capsule review for submission to the marketplace). To do so, you need to create natural language training for Search
Since you are asking for input at a prompt, you need to create a training that will be used when prompting for Search
Training source for this would look like:
[g:Search:prompt] (sample search text)[v:Search]
Or in the UI
Definitely check out the sample code at https://github.com/bixbydevelopers for more examples. A simple example of input would be in https://github.com/bixbydevelopers/capsule-sample-fact - note the training that uses tags
In addition to Pete's response, I would recommend taking a look the design principles for Bixby development. These principles will guide you in making a targeted capsule that solves the use case you would like to address.
Related
I have text output that contains "--John Doe" to indicate that the source of the quotation is John Doe. Bixby is reading it as "minus John Doe". I want to read it as "pause John Doe".
I have enclosed the speech() in tags.
dialog (Result) {
match: Content (text)
if ($handsFree) {
template ("\n\n") {
speech ("<speak>#{value(text)}</speak>")
}
} else {
}
}
Conversation pane in debug:
Dialog/<speak>I claim to be an average man of less than average ability. I have not the shadow of a doubt that any man or woman can achieve what I have, if he or she would make the same effort and cultivate the same hope and faith. --Mohandas Karamchand Gandhi</speak>
Template
<speak>#{value(text)}</speak>
It pronounces the -- as "minus". I want it to be a pause.
Bixby supports limited SSML and I don't think the <break/> tag is supported yet (you could give it a try), but that is the tag you would want. Inside this tag, you can specify how long you want to break for, e.g. <break time="1s"/> or <break time="500ms"/>. So applying this to your example:
<speak>I claim to be an average man of less than average ability. I have not the shadow of a doubt that any man or woman can achieve what I have, if he or she would make the same effort and cultivate the same hope and faith. <break time="1s"/> Mohandas Karamchand Gandhi</speak>
In your action JS, you would need to have something like
let quote = 'I claim to be an average man of less than average ability. I have not the shadow of a doubt that any man or woman can achieve what I have, if he or she would make the same effort and cultivate the same hope and faith. --Mohandas Karamchand Gandhi';
quote = quote.replace('--', '<break time="1s"/>');
To replace the -- with the appropriate SSML tag.
The documentation doesn't say Bixby supports this tag yet. About a month ago, some of the Bixby staff said in Slack that more SSML support is "coming very soon", but I don't think it has arrived yet.
User error. π Replace the two "minuses" with β (em-dash). Maybe that'll help?
There is no quick way, nor SSML would help in this case. You should use different content for display and speech.
define a structure with display and speech property. TextDisplay and TextSpeech are just Text primitive concept.
structure (MyStruct) {
property (display) {
type (TextDisplay) min (Required) max (One)
}
property (speech) {
type (TextSpeech) min (Required) max (One)
}
}
When creating such concept, make sure do the the replacement in your JS script so that myStruct.display = "xyz -- John"; and myStruct.speech = "xyz .. John";
define view file, the trick is that each dot in speech will create a little pause. You can control the length of pause by adding more dots.
result-view {
match: MyStruct(this)
message {
template ("#{value(this.display)}") {
speech ("#{value(this.speech)}")
}
}
}
If you use γ, reading it to be paused
like this:
template ("Hello #{value(text)}") {
speech ("Helloγ #{value(text)}")
}
and
quote.replace() is not good,
Try to add source (property) to your Content structure.
Content.model.bxb
Structure (Content) {
property (quote) {
type (viv.core.Text)
min (Require)
}
property (source) {
type (viv.core.Text)
min (Require)
}
}
and your dialog
dialog (Result) {
match: Content (content)
if ($handsFree) {
template("#{value(content.quote)} -- #{value(content.source)}") {
speech("#{value(content.quote)} γγ #{value(content.source)}")
}
}
}
I'm trying to take the data (concept) from a card a user selects from a results view containing multiple cards and instead of presenting the information from that card in a more detailed view i'm trying to use the properties of the Concept the card displays, ie: Song author, title ... and transform that into a audioPlayer.AudioInfo concept and start playing the audio.
I am familiar with how the audio demo capsule plays audio, where the audioPlayer.AudioInfo is first build, an then passed to the audio player in the same action: https://github.com/bixbydevelopers/capsule-samples-collection/tree/master/audio
action (PlaySessionOfDay) {
type (Search)
collect {
computed-input (sessionToPlay) {
description (Fetch the sessions to be played)
type (audioPlayer.AudioInfo)
min (Required) max (One)
compute {
intent {
goal: BuildSessionOfDayAudioInfo
}
}
hidden
}
computed-input (session) {
description (By passing in the AudioInfo object to the PlayAudio action, we ask the client to play our sound.)
type (audioPlayer.Result)
compute {
intent {
goal: audioPlayer.PlayAudio
value: $expr(sessionToPlay)
}
}
hidden
}
}
output (Result)
}
How an can you use the selected Song card from the list of cards as the input into the PlaySessionOfDay action and then pass it to an action like BuildSessionOfDayAudioInfo, to create an audioPlayer.AudioInfo.
It looks like you can't have compute block
compute {
intent {
goal: BuildSessionOfDayAudioInfo
}
}
unless you are using computed-input (sessionToPlay).
Edit: I think some of the trouble is because by default cards clicked on in a list-of (songs) view invoke a details view. Is there any way to avoid this and use the selected data as the input to an action?
Is there any way to avoid this and use the selected data as the input to an action?
Yes, set has-details (false) in your view model, read more here
You need to add on-click with the intend PlaySessionOfDay
You would also need implement PlaySessionOfDay so it could take an input (I assume you have more than one content to play)
I have downloaded the sample capsule and implemented into my capsule and it is working, but now i need to pass few ids and generate the content for songs.
So my intent on followup will be
intent{
goal:PlaySongs
value-set:MultipleArtistId{$expr(singleArtistEvent.artistId)}
}
My PlaySongs action file read like this
action (PlaySongs) {
type (Search)
collect {
computed-input (songToPlay) {
description (Create the playlist to play)
type (audioPlayer.AudioInfo)
min (Required) max (One)
compute {
intent {
goal: GetMeArtistSong
value-set: MultipleArtistId
}
}
hidden
}
computed-input (play) {
description (By passing in the AudioInfo object to the PlayAudio action, we ask the client to play our sound.)
type (audioPlayer.Result)
compute {
intent {
goal: audioPlayer.PlayAudio
value: $expr(songToPlay)
}
}
hidden
}
}
output (Result)
}
GetMeArtistSong action file reads like this
action (GetMeArtistSong) {
type(Search)
description (Artist Song)
collect {
input (artistId) {
type (MultipleArtistId)
min (Optional) max (One)
}
}
output (audioPlayer.AudioInfo)
}
I am unable to get the artist id on GetMeArtistSong js file.
What are things i am doing wrong?
And what is hidden for? please explain.
hidden means the linked JS function do not need to list that input as argument. Without hidden, your JS function need to have both songsToPlay and play as argument.
Without the actual JS file and endpoints file, I can only speculate your question about artistId. It should not be related to audio player. Check endpoints and do console.log(), my feeling is that the action model and JS function are not properly linked. Also, you may want to change to min(Required) to enforce an input.
I would like to collect an address input for an action "evaluate". Ideally the behavior would be something like this:
1) Evaluate is initiated
2) a default address is pulled from user profile,
user is asked if they would like to use this address
3) if no default address or user does not want to use it,
prompt user for an address
4) Evaluate action runs with either default address or custom input address
What I am thinking of doing is adding 2 constructor actions that could potentially return a geo.Address object, ReturnSelfAddress and GetCustomAddress. ReturnSelfAddress will collect an address from the self library capsule and GetCustomAddress will prompt the user to enter an address as a geo.UnstructuredAddress and convert that into a regular geo.Address.
The input to the Evaluate action is this:
input (address) {
type (geo.Address)
min (Required)
max (One)
default-init {
intent {
goal: ReturnSelfAddress
}
}
}
Then I would have a confirmation view that would confirm ReturnSelfAddress to let the user select that if desired. If ReturnSelfAddress fails, then Evaluate will still look for a geo.Address input. I would have an input-view that would match the geo.Address concept and prompt the user to input a geo.UnstructuredAddress. Something like this (not sure if this is 100% correct):
input-view {
match: geo.Address(this)
message ("What is your street address?")
render{
form {
elements {
text-input {
id (address)
label("Address")
required (true)
type (geo.UnstructuredAddress)
}
}
on-submit {
goal: GetCustomAddress
value: viv.core.FormElement(address)
}
}
}
}
Alternatively, if the user rejects the default, then I will have an on-abort goal of GetCustomAddress that would prompt the user:
on-abort {
intent {
goal: GetCustomAddress
}
}
This seems to be very involved, and I am questioning if there is a feature that i might be missing that will help me get the desired behavior. So i guess i have 2 questions:
1) Before i go too deep down this rabbit hole, will this idea work?
2) Is there a better way to get the desired behavior of "try for default and if none or user rejects, prompt for input"?
You can try the confirmation view, but here is an easier way you might find useful.
Define the input in action model with default-init and prompt-behavior (AlwaysElicitation)
input (email) {
type (TypeTextEmail)
min (Required) max (One)
default-init {
intent {
goal: FetchEmailFromName
value: $expr(name)
}
}
prompt-behavior (AlwaysElicitation)
}
Define input view to overwrite the default if user want to
input-view {
match: TypeTextEmail(this)
render {
form {
elements {
text-input {
id (this)
type (TypeTextEmail)
label ("Email:")
max-length (50)
value ("#{value(this)}")
}
}
on-submit {
goal: TypeTextEmail
value: viv.core.FormElement(this)
}
}
}
}
You can download and try the training example in example.inputview
For confirmation view, please refer the example.shirt on Github
Currently I am trying to set up a few continuation actions after an interaction. One such continuation will send an email to the user with the results from the last action. I set up the action that will get an email address and send the email. To fill this input, i would like to offer the email addresses contained in the profile/self capsule as selection options and alternatively allow the user to input a custom email.
i set up a default input to get email addresses from the profile capsule and then offer those as options for the email input:
input (emailAddress) {
type (contact.EmailAddress)
instantiation-behavior (ShowDefaultValueDecision)
min (Required) max (One)
default-init {
intent {
goal: ReturnSelfEmail
}
}
}
Then i display them in an input-view using selection-of:
Here is my view:
input-view {
match: contact.EmailAddress(this) {
to-input: EmailResults
}
message ("What is your Email address?")
render{
selection-of (this) {
where-each (email) {
paragraph {
value {
template ("#{value(email)}")
}
style (Detail_M)
}
}
}
form {
elements {
text-input {
id (emailAddress)
label("Email Address")
required (true)
type (contact.EmailAddress)
}
}
on-submit {
goal: contact.EmailAddress
value: viv.core.FormElement(emailAddress)
}
}
}
}
In that view, I tried to add a form component as well but this does not work. Any ideas on how to have a custom input option in addition to the selections? Or another way to deal with a situation where the selections do not satisfy the user?
You can't render a form after you've rendered a selection-of.
My IDE shows this error - does yours?
"Unreachable statement" means that that part of the code will never run.
Anyways, one possible way to model this is to offer a selection view of the user's real email addresses, and one final entry which is a dummy email address called "input my own." (this uses selection-of)
If that selection is made, you can do throw an error in your JavaScript, and replan to a goal such as EnterCustomEmail. (this uses the form).
Here is another way to approach the problem.
In the result-view of the interaction (assuming that the email is sent at the end of the interaction), I would ask the user a followup question "Should I send a confirmation email to the <email> on your profile.?"
If the user responds "Yes" then the Action associated with the goal for the on-confirm will send an email to the user.
If the user says "No", the Action associated with the goal for on-deny should prompt the user for an email address.
This approach uses the conversational features of the Bixby platform and makes this interaction a more natural experience for the end-user.