Author Topic: Confirmation and Basic Responses  (Read 21664 times)

Gary

  • Administrator
  • Hero Member
  • *****
  • Posts: 2800
Confirmation and Basic Responses
« on: June 12, 2018, 09:54:38 PM »
For a good while, it's been possible to get VoiceAttack to handle a user response (https://groups.google.com/forum/#!topic/voiceattack/rWyhE7Qyjco  remember this one?).  This would usually take a handful of commands that would set a variable and a set of asynchronous loops to see if variables are set and/or a timeout was exceeded.  This method works great for most cases and can be very flexible if done right.

Sometimes you just need something quick, direct or concise to get the job done.  In VA versions v1.7.10+ (currently beta), the 'Wait for Spoken Response' action is available.  What this action does is attempt to combine a few of the elements that usually make up user spoken response handling in VA:
  • Establishing a set of expected responses
  • Looping and waiting for a valid response to occur
  • Storing the response for further examination so the command can decide what to do
  • Handling responses other than what is expected
  • Handling what happens when a user takes too long to respond (timeout)

The new, 'Wait for Spoken Response' action (Other > Advanced > Get User Input > Wait for Spoken Response) encapsulates the main portions of getting a user's spoken response.

The expected responses are established by setting the, 'Responses' value.  This can be a single response, such as, 'yes', or multiple responses separated by semicolons 'yes;no;maybe'.  The Responses box will handle dynamic responses, such as, '[deploy;fire][all;][weapons;squirrels;]'.  The only limitation is that there can only be up to 250 possible responses per action, so, pick your responses carefully ;)

Looping and waiting for a valid response is handled internally.  The action will wait until the user has issued a spoken response before continuing.

When the user issues a spoken response, the action then takes whatever the user said and puts it into a text variable that you specify in the, 'Text Variable' box.  After the spoken phrase is placed in the variable, the action exits and then the variable can be inspected.  You can make a decision at that point, using conditional statements (for example, if the variable's value equals, 'fire' then do something (press a key, play a sound).  else, do nothing (or something else lol).

The user may say something that is incorrect or not in the list of expected responses.  Under normal circumstances, the action will not continue if the user's response is not in the list.  So, if the expected responses are 'yes', 'no' and 'maybe', and the user is saying, 'ok' or 'go', the action will continue to wait until the response is correct.  For most cases, this is acceptable.  However, there may be times when you want to give feedback to the user when this happens.  Checking the, 'Continue on any Speech' option will tell the action to continue the command no matter what is said.  The value that is placed in the variable will be, '@@invalid' (without the quotes).

There are times when the user will take too long to respond (or give a proper response).  You can set the amount of time that the action will wait in the, 'Timeout' input box.  If the number of seconds is exceeded, the command will continue and there will be no value placed in the indicated text variable (the value will be Not Set (null)).


Let's take a look at a few examples to see what can be done (each of the sample commands are included in the profile attached to this post).

First, let's look at a basic confirmation command:

Code: [Select]
Say, 'Do you like ice cream?'
Wait for spoken response: 'yes;no'  (timeout set to 15 seconds, response placed in, 'myVariable' text variable)
Begin Text Compare : [myVariable] Equals 'yes'
    Say, 'I thought you would say that.'
Else If Text Compare : [myVariable] Equals 'no'
    Say, 'No? I'm pretty sure you meant to say yes. Who doesn't like ice cream? Weirdo.'
End Condition

The first command (named, 'ask me', in the included profile) first asks the question, 'Do you like ice cream?' (with text-to-speech).  Then, the, 'Wait for spoken response' action waits for the user to say either, 'yes' or 'no'.  Depending on what the user says, the command will act accordingly with the proper text-to-speech response.  If the user waits longer than 15 seconds, the command will continue on and do nothing else.


A slightly modified version of, 'ask me' is, 'ask me again':

Code: [Select]
Say, 'I'll ask again. Do you like ice cream?'
Wait for spoken response: 'yes;no'  (timeout set to 15 seconds, response placed in, 'myVariable' text variable)
Begin Text Compare : [myVariable] Equals 'yes'
    Say, 'I thought you would say that.'
Else If Text Compare : [myVariable] Equals 'no'
    Say, 'No? I'm pretty sure you meant to say yes. Who doesn't like ice cream? Weirdo.'
Else If Text Compare : [myVariable] Has Not Been Set
    Say, 'You waited too long to reply. You must be eating ice cream. Rock on.'
End Condition

This is exactly the same as, 'ask me', but we've added one more check to see if the value of myVariable has not been set.  When the user takes too long to reply, there is no value placed in the variable (that is, Not Set... programmers call it, 'null').  The command then has a chance to reply when this situation arises.


The last basic example shows how to handle unexpected responses.  The, 'ask me a third time' command shows how to do this:

Code: [Select]
Say, 'Come on, now. Do you like ice cream?'
Wait for spoken response: 'yes;no'  (timeout set to 15 seconds, response placed in, 'myVariable' text variable, 'Continue on any Speech' checked)
Begin Text Compare : [myVariable] Equals 'yes'
    Say, 'I thought you would say that.'
Else If Text Compare : [myVariable] Equals 'no'
    Say, 'No? I'm pretty sure you meant to say yes. Who doesn't like ice cream? Weirdo.'
Else If Text Compare : [myVariable] Equals '@@invalid'
    Say, 'I didn't understand what you just said. Don't talk with your mouth full.'
Else If Text Compare : [myVariable] Has Not Been Set
    Say, 'You waited too long to reply. You must be eating ice cream. Rock on.'
End Condition

What was added in this example was that the, 'Continue on any Speech' checkbox was checked, as well as the condition check for the value of, '@@invalid' in the text variable.  '@@invalid' (without the quotes) is what is placed in the text variable if the response was not expected.



Now, for an advanced example (I'm sure this is what you are looking for).  This command is called, 'engage enemy' in the sample profile:

Code: [Select]
Say, 'Engaging enemy. What are your orders?'
Marker: getResponse
Wait for spoken response: 'fire[weapons;];hail;shields[up;];evade;red alert;send flowers'
Begin Text Compare : [~myVar] Contains 'fire'
    Say, 'Confirm firing weapons, captain'
    Wait for spoken response: 'yes;fire;no'
    Begin Condition : [~myConfirm] Equals 'yes' OR [~myConfirm] Equals 'fire'
        Say, 'Firing the weapons'
    Else
        Say, 'Standing down. Weapons not fired.'
    End Condition
Else If Text Compare : [~myVar] Equals 'hail'
    Say, 'Frequency clear'
Else If Text Compare : [~myVar] Contains 'shield'
    Say, 'Shields raised.'
Else If Text Compare : [~myVar] Equals 'evade'
    Say, 'Prepare for evasive action. Full power to thrusters.'
Else If Text Compare : [~myVar] Contains 'alert'
    Say, 'Red alert. All required personnel report to the bridge at once.'
Else If Text Compare : [~myVar] Equals '@@invalid'
    Say, 'I did not understand that. What are your orders?'
    Jump to Marker: getResponse
Else If Text Compare : [~myVar] Has Not Been Set
    Say, 'You have taken too long to respond. Disengaging.'
Else
    Say, 'I'm not sure that's a good idea. Disengaging.'
End Condition

Some things to note about the, 'Wait for Spoken Response' action in this example is that its timeout is set to 10 seconds, the 'Continue on any Speech' option is checked and the text variable is ~myVar (note that it is locally-scoped).  Also, the responses are set up by using the dynamic command syntax (you know... with all the brackets. This is not necessary, btw).

The command starts off by asking (via TTS), 'Engaging enemy. What are your orders?'.  You can then say things like, 'hail', 'shields up', 'evade' etc..  If you say something that is not in the response list (again, this is enabled by checking the, 'Continue on any Speech' option), the command will respond with, 'I did not understand that. What are your orders?' (because the variable's value is set to, '@@invalid').  Note that there is a 'jump to marker' action in this section that jumps control way back up to near the top (up to Marker: getResponse).  This starts the waiting process over again and allows you to give an expected response.  If you happen to take too long to respond (after ten seconds, which is indicated in the 'timeout' value of the action), the command will let you know about it and then nothing happens (the command just exits). 

If you happen to say that you want to fire your weapons, the command will then ask you to confirm your choice (with possible replies of 'yes', 'no' or 'fire'.  This is kind of a small example of response, 'branching').  If you say anything other than, 'yes' or, 'fire', the command will exit.  Otherwise, the order is given and now you're in for a fight ;) 


I hope you enjoy this handy little feature ;)