Has anyone else ever created any generic "AutoVoice functions" to use within other tasks?

858 views
Skip to first unread message

nicro...@gmail.com

unread,
Aug 5, 2014, 5:00:57 PM8/5/14
to joao...@googlegroups.com
Hi everyone,

I recently created a reddit thread about this topic (https://www.reddit.com/r/tasker/comments/2cnfcs/has_anyone_else_ever_created_any_generic/), but it probably makes sense to post this here too.

------------------------------------------------------------------------------

I've been working on creating various hands-free interfaces to things I do on my phone, and like any programmer doing anything like this, I quickly realized that functions would be a much better way to go for some of the more common voice input needs within a task.

For example (and my only "proof of concept" example, at the moment) is a function for a voice assistant to confirm something with the user...typically a simple yes/no response is what I've needed so far (but it could easily become more). If I'm searching through contacts and I want to confirm that the contact found is the correct contact, I might confirm with the user... If I want to send a text message and confirm the message before sending... These things shouldn't be repeated over and over. They should be as simple as a "Perform Task: Confirm" with a paramter of the question to prompt the user with...or as close to that as possible.

So, given that...here's a simple solution that I came up with earlier (but I really feel there's probably a better way). I've already thought of a few possible improvements but I'll just provide what I've tested for now.

First, I created a task called "Confirm". %par1 is the text you'd like the user to be asked. This is the generic function to be called from within a task.
1. Variable Clear: %Confirm
2. Variable Clear: %CurPrompt
3. Variable Clear: %CurQuestionID
4. If %par1 !Set
5. Flash: "When using the 'Confirm' task, you must provide the question for the user as %par1."
6. Stop
7. End If
8. If %par2 !Set
9. Flash: "When using the 'Confirm' task, you must provide the name of the calling task as %par2."
10. Stop
11. End If
12. Variable Set: %WaitingTask to %par2
13. Say: "%par1"
14. AutoVoice Set Cmd Id: Confirm
15. AutoVoice Recognize: Prompt Text: %par1

Next was the response creation. I created 2 profiles (could be more though) for the responses. One called "Confirm: Yes" and one called "Confirm: No". They each have event behavior checked and last command ID set to "Confirm". The command filter for each should be self explanatory (mine happen to be a big regex "or" list for all possible things I might say in each instance). For each of these I also went into the "advanced" AutoVoice configuration to set a variable (called "response") to a value ("Positive Response." for the yes profile and "Negative Response" for the no profile). Finally, they each call the same task called "Confirm Response":
1. Variable Set: %Confirm To %response
2. Variable Clear: %CurPrompt
3. Variable Clear: %CurQuestionID
4. Variable Clear: %WaitingTask

Lastly, I created another task called "Confirm Test" to test the function:
1. Perform Task "Confirm": %par1: "Please provide a positive or negative response.. Like yes or no"
2. Wait Until: %Confirm Is Set
3. Flash: %Confirm

I gave the above a simple voice command profile to get it started, on AutoVoice recognize "confirm". But now, without doing all of this again, I can get a simple yes/no voice prompt in any task. I can only think of a handful of use cases right now, but I feel like most everything complex has a lot of repetition that something like this would mostly eliminate.

At this point, we need some additions to allow for a catch-all (or cancel command) to help compensate for a possible state of "limbo".

For this, we need a new task called "Stop Waiting Tasks":
1. If %WaitingTask Is Set
2. Stop: %WaitingTask
3. End If
4. Variable Clear: %WaitingTask

Once we have that, lets create a new profile triggered by "AutoVoice Recognize" for "Cancel" with no last command ID set. This task should simply call "Stop Waiting Tasks". Now we can stop at any time by saying "cancel" and it won't lock us in limbo if we do.

Though, better still might be to have it repeat the same question again if the match fails so failure in the speech recognition won't necessarily disrupt the task flow (what happens if we don't say "yes", "no", or "cancel"?). For that we'll need two more variables: one for the previous question posed to the user and one for the Command ID used (since Confirm won't be our only function like this). For these, I'll use "%CurPrompt" and "%CurQuestionID".

In the "Confirm" task, we'll need to add these lines somewhere before the last line (I put mine just under the "Array Push" line):
1. Variable Set: %CurPrompt to %par1
2. Variable Set: %CurQuestionID to Confirm

Then we create one more profile, called "Failed Recognition", triggered on "AutoVoice No Match" with a Last Command ID set to "Confirm" so it only triggers during the question we care about. This should trigger a task, also called "Failed Recognition":
1. Say: "Sorry, I didn't catch that."
2. Say: "%CurPrompt"
3. AutoVoice Set Cmd Id: %CurQuestionID
4. AutoVoice Recognize: Prompt Text: %CurPrompt

Now, with all of this in place (and the modifications above in "Confirm Response"), when the "Confirm" voice command is issued, it will ask for the question and it won't stop until it's satisfied with either a response or a "cancel" command.

Given all of that... Has anyone else tackled this concept at all? What have you come up with? What all can we do to improve upon this idea here? I do realize that this became a bit of a How-To even though that wasn't the original intention. Input is still very welcome...if you can improve upon the idea, I'd love to hear about it.

João Dias

unread,
Aug 5, 2014, 6:43:36 PM8/5/14
to joao...@googlegroups.com
Just a tip: you don't need to use Last command Ids anymore for situation like these :) You can simply use the voice command results in the same task :) Hope this helps!



--
You received this message because you are subscribed to the Google Groups "joaomgcd" group.
To unsubscribe from this group and stop receiving emails from it, send an email to joaomgcd+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

nicro...@gmail.com

unread,
Aug 5, 2014, 6:52:33 PM8/5/14
to joao...@googlegroups.com
When using the voice command results within the same task, what's the recommended way to have a multiple-choice scenario? My example here only had 2 options, and that can be done easily inline like that, but what if it were a "main menu" scenario with 5+ options or something similar? Is there an "easy" way to do that inline as well? Or does it result in a large if/else tree?

João Dias

unread,
Aug 5, 2014, 7:06:39 PM8/5/14
to joao...@googlegroups.com
If you want to make it a bit more dynamic you could do this:
- have a task that handles each possible response. For example, have a task called "Answer yes", another called "Answer no" and another "Answer maybe"
- after the AutoVoice action perform the task "Answer %avcomm". 
- Done :)

nicro...@gmail.com

unread,
Aug 5, 2014, 7:25:15 PM8/5/14
to joao...@googlegroups.com
That might work for simple, single word situations, but what about more complex regex patterns?

For example... My confirm example ended up with these filters:

Yes: (?:yes|please|(?:could|would) you|yeah|yep|affirmative|certainly|you bet|sure|absolutely|why not)

No: (?:no|nope|negative|don(?:')t)

Cancel: (?:cancel|nevermind)


With word lists, I can make everything respond well enough to just about any natural language response I can think of...but this kind of flexibility doesn't look like it would work well with your implementation.

Also, by using the Last Command IDs we can still possibly fire off multiple responses at once from within an isolated context, right? So, I could have a main menu with multiple options, then a sub menu with its own separate options, and within each menu context I could launch multiple commands specific to the menu, I think.

Also, I think I'd ultimately like to build a few other functions that would probably go a bit beyond just a basic linear approach. So, if I were to voice command into an email menu, then in no particular order I could have voice commands to set the subject, recipient, etc., all as needed.

I guess I should say too... I had been doing things in-line before, but ultimately decided that there would be a lot more flexibility with something more like this. I think if there were a way to have a list of command filters instead of a single command filter per AutoVoice recognize, I could probably achieve something similar in-line (something that might emulate a switch/case type situation?). I have no idea how feasible nor what other side effects this would have though...

João Dias

unread,
Aug 5, 2014, 7:35:37 PM8/5/14
to joao...@googlegroups.com
Yeah, for more complex situation like yours, you should stick to last command id :)


easiuser

unread,
Aug 6, 2014, 9:46:35 AM8/6/14
to joao...@googlegroups.com, nicro...@gmail.com
This is what I use for simple responses.  When I call this routine, %par1 is the voice prompt and %par2 contains acceptable responses.  For example when I receive a new SMS I call it like so:
 
Perform Task [ Name:vGetResponse Priority:%priority+1 Parameter 1 (%par1):New SMS from %buffer2 : %buffer3 Parameter 2 (%par2):yes|no|save|reply Return Value Variable:%response Stop:Off ]
The task will return one of the responses in %par2 or unknown (if nothing is heard) or invalid (if response does not match any of the acceptable responses.  Then I can process accordingly.  I am sure this could work much better if I could develop better regex statements and add addtional responses
 
vGetResponse (404)
 A1: Variable Set [ Name:%yes To:(\W|^)(yes|acknowledge|agree|affirmative|good|okay|ok|okie dokie|true|yea|aye|by all means|certainly|of course|yep|very well|absolutely|send)(\W|$) Do Maths:Off Append:Off ]
 A2: Variable Set [ Name:%negative To:(\W|^)(no|negative|absolutely not|no way|never|not at all|cancel|void|forget it|negatory|reject|refuse|nullify|skip|nix|nada)(\W|$) Do Maths:Off Append:Off ]
 A3: Variable Set [ Name:%reply To:(\W|^)(reply|responed|retort|return|remark|answer|rebutt)(\W|$) Do Maths:Off Append:Off ]
 A4: Variable Set [ Name:%save To:(\W|^)(save|hold|later|keep)(\W|$) Do Maths:Off Append:Off ]
 A5: Variable Set [ Name:%retry To:(\W|^)(retry|again|once more|one more time|return)(\W|$) Do Maths:Off Append:Off ]
 A6: Variable Set [ Name:%par1 To:I'm listening... Do Maths:Off Append:Off ] If [ %par1 !Set ]
 A7: Variable Set [ Name:%par2 To:open Do Maths:Off Append:Off ] If [ %par2 !Set ]
 A8: Perform Task [ Name:bpSuspend Priority:%priority+1 Parameter 1 (%par1):vGetResponse Parameter 2 (%par2): Return Value Variable: Stop:Off ]
 A9: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
 A10: Say [ Text:%par1 Engine:Voice:%ttsEngine Stream:3 Pitch:5 Speed:5 Respect Audio Focus:Off Network:Off Continue Task Immediately:Off ]
 A11: AutoVoice Recognize [ Configuration:
Prompt Text: %par1
Language Model: Free Form
Voice command with headset
Timeout: 15
Command: "all"
Don't Trigger Conditions: true Package:com.joaomgcd.autovoice Name:AutoVoice Recognize Timeout (Seconds):120 ]
 A12: Perform Task [ Name:bpResume Priority:%priority+1 Parameter 1 (%par1):vGetResponse Parameter 2 (%par2): Return Value Variable: Stop:Off ]
 A13: Wait [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ]
 A14: [X] Popup [ Title:Response from AV Recognize Text:%avcommsnofilter() Background Image: Layout:Popup Timeout (Seconds):5 Show Over Keyguard:On ]
 A15: Return [ Value:unkown Stop:On ] If [ %avcomm !Set ]
 A16: Return [ Value:%avcomm Stop:On ] If [ %par2 ~R open ]
 A17: Return [ Value:yes Stop:On ] If [ %par2 ~R yes & %avcommsnofilter() ~R %yes ]
 A18: Return [ Value:no Stop:On ] If [ %par2 ~R no & %avcommsnofilter() ~R %negative ]
 A19: Return [ Value:reply Stop:On ] If [ %par2 ~R reply & %avcommsnofilter() ~R %reply ]
 A20: Return [ Value:save Stop:On ] If [ %par2 ~R save & %avcommsnofilter() ~R %save ]
 A21: Return [ Value:retry Stop:On ] If [ %par2 ~R retry & %avcommsnofilter() ~R %retry ]
 A22: Return [ Value:invalid Stop:On ]

Marta Hintz

unread,
Nov 11, 2014, 8:26:36 PM11/11/14
to joao...@googlegroups.com, nicro...@gmail.com
easiuser, do you use this for a yes/no prompt also?  If so, care to elaborate in a quasi script that I can use.  I tried to follow your sms one you had, but it was a bit too complex with the sms task.  still trying to figure out how those parmeters work.  

thanks! 

easiuser

unread,
Nov 12, 2014, 10:51:14 AM11/12/14
to joao...@googlegroups.com, nicro...@gmail.com
I do use this for all my voice responses.  This routine will only return "unknown", "invalid" or those listed in %par2.  That way the calling routine does not need to do any pattern matching of the voice results and has a limited number of responses to deal with.  For a simple yes/no prompt I would do the following;
 
Call the task with
%par1 set to whatever I want to be prompted with ie "Would you like some coffee?"
%par2 set to acceptable responses ie "yes|no"
 
The task will say the prompt and then ...
If I respond with anything that matches %yes ie "yes, ok, absolutely, ..." the return value will be "yes".
If I respond with anything that matches %negative ie "no, never, forget it, ..." the return value will be "no".
If I respond with anything that doesn't match these values the return value will be "unknown"
If I do not respond the return value will be "invalid"
 
The calling routine can then act based on the return value.

Marta Hintz

unread,
Nov 12, 2014, 11:40:21 AM11/12/14
to joao...@googlegroups.com
Ok, thanks this helps alot! Just upgraded my phone to a note 4 not rooted, and wanting to start over on my spaghetti tasker tasks. I am trying to go more modular now. Takes a bit of effort to think all this through, but in the long run I think the tasks run with less problems and easier to troubleshoot.

nicro...@gmail.com

unread,
Dec 23, 2014, 5:08:03 PM12/23/14
to joao...@googlegroups.com, nicro...@gmail.com
Thanks for this suggestion. I haven't really had a lot of time to tinker with this again until recently, but this method seems a bit cleaner and easier to follow, especially as complexity increases.

Based on this, I ended up creating two helper tasks. One called "Set Global Voice Responses" that sets a bunch of variables with the response regexs in what effectively amounts to a response table (called at startup in an init profile). The other is called "Check Voice Response" and accepts the %avcomm input as %par1 and the short names for the requested responses as %par2...it basically ends up as a container task for the Return calls.

The final effect now is that I can call AutoVoice recognize, then call "Check Voice Response" with %par1=%avcomm and %par2="yes,no,cancel" and it will return either "Yes", "No", "Cancel" or "Invalid" if none of the responses were found. When I need an additional response, I can define a new response regex and place it in my "Set Global Voice Responses" task, then add a return case in my "Check Voice Response" to effectively assign the short name. Now, that short name will be valid in the list provided to %par2 when calling "Check Voice Response".

With this, it's still possible to have one-off responses by checking %avcomm after receiving "Invalid" from "Check Voice Response"...but it's actually less overall effort to simply define another global response. I won't know what is truly better in practice until I get around to re-adding my other task fragments back into the mix...but the goal is to have them be generic and reusable, so the global table may not be end up being too bad in the long run.

I'm still tempted to revisit a design idea that's similar to the original one I posted though (one utilizing profile event triggers instead of inline if checks) since I think it still might result in a little better conversational flow control...but as mentioned earlier, I do think it will end up being a bit more complex. If it ever gets fleshed out to a usable format, I'll do what I can to simplify and post the results.

nicro...@gmail.com

unread,
Dec 24, 2014, 8:46:26 PM12/24/14
to joao...@googlegroups.com, nicro...@gmail.com
Okay...after playing with this some more, I think I've found the "right" way to handle this sort of thing.

AutoVoice or AutoContacts (and probably others) functions can often be reduced down to a simple input string that results in a simple output string. Given this, here's what I've started to do:

- Create an "AutoVoice" tab in Tasker.
- Within, create an "Ask" task.
- The "Ask" task should look like:
1. Say "%par1"
2. AutoVoice Recognize
- Prompt Text: %par1
3. If %avcommnofilter !Set
4. Say "Sorry, I didn't catch that..."
5. Goto #1
6. End If
7. Return %avcommnofilter


Now, from within any other task, you can use:
n. Perform Task "Ask", %par1="<question text>", Return Value="%response"
n+1. If %response R~ "(regex)"
n+2. /* Stuff */
n+3 End If

I've been using my "global table" to store regex responses possibilities in variables and using those variables to compare against the %response variable. It looks something like this:

n. If %response R~ %Response_Affirmative
n+1. /* Do stuff */
n+2. End If


This all has the nice benefit of encapsulating any repetitive programming to get the voice response within the sub-task (failed recognition, canceled recognition, etc.). Each function could store possible responses in local variables, or generic responses could go into global variables for possible use anywhere...but all of the functionality is ultimately encapsulated and reusable with essentially any overall Tasker strategy.

I've started to use this same basic principle for my AutoContacts functionality with a fair degree of success as well. In retrospect, this use seems rather obvious, but since I didn't really stumble across it until now I figured it would be nice to share. I think my mental hurdle before was related to the number of variables returned by these plugins and not knowing the Tasker interface/style as well as I should...but if we just let the sub-tasks handle very specific instances, we can get a lot of generic use in addition to the flexibility that's already provided.

João Dias

unread,
Dec 26, 2014, 11:33:30 AM12/26/14
to joao...@googlegroups.com
Thanks for sharing! :)

nicro...@gmail.com

unread,
Dec 27, 2014, 1:21:35 PM12/27/14
to joao...@googlegroups.com
Okay...over the last few days I've had some time to really play with some options. I've come to some conclusions that depend upon your level of need/involvement with voice commands.

For very quick and/or anyone wanting something that works reasonably well without taking a ton of effort would do best to encapsulate easiuser's method inline or into its own task as he's essentially shown above. It is best to put this into it's own task though, and to have that task handle any necessary repetition due to canceling voice input or handling unrecognized input (this really cleans-up the calling tasks).

If you plan to create many similar functions, it becomes very beneficial to store your common responses in global variables. For example, a "cancel" option may appear in many different instances across many menus and it's really nice to have consistency. This is probably the easiest way to branch out. Using no further innovation than this, I was able to create a rather elaborate and well-functioning voice interface to send email.

Though, there was one thing that I still felt might be extremely beneficial that AutoVoice offers that is lost through this method... The ability to create variables during voice recognition via regex. Using what I've been casually referring to as the "Last Cmd ID" method, you can have that back. In addition to that, any response created can actually be reused in any instance as each potential response is enabled/disabled prior to each AutoVoice recognize.

I don't have a clean example (but I'm close)... I'll expand my setup with a few more examples and get them cleaned up, then I'll come back and post them too. For now, a quick explanation of the method:

The first core concept, is that each potential voice response should be contained within it's own AutoVoice Recognize event profile. I have been prefixing mine with "Response:" and I have this list:
Response: Unrecognized (This one is actually an AutoVoice No Match event)
Response: Cancel
Response: Yes
Response: No
Response: Word (Receives a single word input from the user)
Response: Line (Receives a single line input from the user)
Response: Text (Receives multi-line input from the user, until the user provides a specific "finished" command to exit...good for the body of an email or SMS message, etc.)

Each of these are set with an appropriate regex command filter, but in addition to that, each has the "Last Command Id" set to a global variable that matches the response name. So, "Response: Cancel" has the corresponding variable %Response_Cancel.

The variable for the Last Command Id is modified with the help of two other tasks "Enable Response" and "Disable Response". It is assumed that "Enable Response" will be called prior to any AutoVoice recognition. It takes a list of responses as %par1 and a Last Command Id to be activated for as %par2. So, calling "Enable Response" with %par1="Yes,No,Cancel" and %par2="MyTask" will set the corresponding Last Command Id variables %Response_Yes, %Response_No, and %Response_Cancel to have the value of "My Task". So long as the calling task also issues the AutoVoice Set Cmd ID action, only the selected responses will be active. Currently, all options are disabled by default, with the exception of Unrecognized and Cancel that are always enabled unless explicitly disabled with the "Disable Response" counterpart (accepts the same %par1 list, but ignores %par2).

So, with that, we have our list of responses moved out into the profile list and each can be enabled/disabled still via the Tasker UI. What we didn't talk about yet, is what these responses do as a part of their corresponding tasks... Thankfully, it's very simple. They all aim to set a single global variable: %AVReturn. The setting of this variable is the act that triggers linear execution/continuation in the calling task. More on this in a moment.

Now we have basic responses set, and we have a way to reuse AutoVoice responses at will. Complexity as increased, but one of the main goals was to keep it simple to use in live use. Lets look a bit at how we use this.

Say we have a task and we want to get a single line of text from the user (like the subject for an email). A task snippet from that task would look something like this:
Perform Task "Query: Line" %par1="What should the message subject be?" Return=%subject

This "Query: Line" task effectively handles any typical voice command tedium and lets us just focus on the return variable. The only "Gotcha" is that this variable can result in "!Unrecognized!" or "!Canceled!" in addition to the subject itself...so some error checking is still recommended (but not required).

And finally, to tie it all together... Here's what the "Query: Line" task looks like.

Variable Set: %cmdID = "Query: Line"
AutoVoice Set Cmd Id: %cmdID
Perform Task: Enable Response, %par1="Line", %par2=%cmdID
Perform Task: Disable Response, %par1="Cancel,Unrecognized"
Say: "%par1"
AutoVoice Recognize: Prompt Text: %par1
If %avcommnofilter !Set
Return "!Canceled", Stop On
End If
Wait, 1s, Until %AVReturn Set // This is how we hold here until the response profiles have triggered and completed
Return %AVReturn, Stop On

The checking against %avcommnofilter being set is required to detect the user hitting the on-screen button to cancel the voice input and other similar events...it's slightly different from the cancel voice command, but I have been treating them the same with the same "!Canceled!" return value for now.


As I mentioned earlier, I'm going to clean-up a lot of my accumulated clutter during this investigation, and I'll make a point to post some working examples soon.

If anyone has any ideas for improvement at this stage, I'm still very open to suggestions/improvements.


On Friday, December 26, 2014 8:33:30 AM UTC-8, joaomgcd wrote:
> Thanks for sharing! :)
>

No problem at all. Thanks for developing and being active with the community!

nicro...@gmail.com

unread,
Dec 28, 2014, 10:35:04 PM12/28/14
to joao...@googlegroups.com, nicro...@gmail.com
And, as promised, here are the basics of what I described last time, along with a simple example task showing their use. I'm still finding minor improvements as I go along, but I think it's starting to get settled in its form. As always, input is definitely welcome.


/* PROFILES *******************************************************************/

Profile: Response: Unrecognized
Event: AutoVoice No Match [ Configuration:Last Command Id: %Response_Unrecognized ]
Enter: Response: Unrecognized
A1: Variable Set [ Name:%AVReturn To:!Unrecognized! Do Maths:Off Append:Off ] 

Profile: Response: Cancel
Event: AutoVoice Recognized [ Configuration:Command: "(\w|^)(cancel|never mind|nevermind|forget it|forget about it)(\w|$) (regex)"
Last Command Id: %Response_Cancel ]
Enter: Response: Cancel
A1: Variable Set [ Name:%AVReturn To:!Canceled! Do Maths:Off Append:Off ] 

Profile: Response: Yes
Event: AutoVoice Recognized [ Configuration:Command: "(\w|^)(yes|yeah|yep|okay|ok|sure|sounds good|affirmative|aye|of course|by all means|certainly|absolutely|very well|alright|all right)(\w|$) (regex)"
Last Command Id: %Response_Yes ]
Enter: Response: Yes
A1: Variable Set [ Name:%AVReturn To:Yes Do Maths:Off Append:Off ] 

Profile: Response: No
Event: AutoVoice Recognized [ Configuration:Command: "(\w|^)(no|nope|no way|negative|absolutely not|definitely not|never|negatory|reject|refuse|nix)(\w|$) (regex)"
Last Command Id: %Response_No ]
Enter: Response: No
A1: Variable Set [ Name:%AVReturn To:No Do Maths:Off Append:Off ] 

Profile: Response: Word
Event: AutoVoice Recognized [ Configuration:Command: "all"
Last Command Id: %Response_Word ]
Enter: Response: Word
A1: Variable Set [ Name:%AVReturn To:%avword1 Do Maths:Off Append:Off ] 

Profile: Response: Line
Event: AutoVoice Recognized [ Configuration:Command: "all"
Last Command Id: %Response_Line ]
Enter: Response: Line
A1: Variable Convert [ Name:%avcommnofilter Function:To Upper Case First Store Result In: ] 
A2: Variable Set [ Name:%AVReturn To:%avcommnofilter Do Maths:Off Append:Off ] 

Profile: Response: Text
Event: AutoVoice Recognized [ Configuration:Command: "all"
Last Command Id: %Response_Text ]
Enter: Response: Text
Run Both Together
A1: If [ %avcommnofilter ~R (end|done|finished|finito|fin|final|complete) ]
A2: Variable Join [ Name:%TextInput Joiner:| Delete Parts:On ] 
A3: Variable Set [ Name:%AVReturn To:%TextInput Do Maths:Off Append:Off ] 
A4: Stop [ With Error:Off Task: ] 
A5: End If 
A6: Variable Convert [ Name:%avcommnofilter Function:To Upper Case First Store Result In: ] 
A7: Array Push [ Name:%TextInput Position:999999 Value:%avcommnofilter Fill Spaces:On ] 
A8: Variable Clear [ Name:%avcommnofilter Pattern Matching:Off ] 
A9: Perform Task [ Name:Enable Response Priority:%priority Parameter 1 (%par1):Text Parameter 2 (%par2):Response: Text Return Value Variable: Stop:Off ] 
A10: AutoVoice Recognize [ Configuration:
Prompt Text: %AVPrompt
Language Model: Free Form
Voice command without headset
Command: "all" Package:com.joaomgcd.autovoice Name:AutoVoice Recognize Timeout (Seconds):120 ] 
A11: If [ %avcommnofilter !Set ]
A12: Variable Set [ Name:%AVReturn To:!Canceled! Do Maths:Off Append:Off ] 
A13: End If 


/* TASKS **********************************************************************/


AutoVoice Example
A1: Perform Task [ Name:Query: Text Priority:%priority Parameter 1 (%par1):Please recite your postal address, one line at a time. Say "done" when finished. Parameter 2 (%par2): Return Value Variable:%response Stop:Off ]
A2: Flash [ Text:Response: %response Long:On ]
A3: Variable Split [ Name:%response Splitter:| Delete Base:On ]
A4: Variable Set [ Name:%newline To:
Do Maths:Off Append:Off ]
A5: Variable Join [ Name:%response Joiner:%newline Delete Parts:On ]
A6: Flash [ Text:Address:
%response Long:On ]
A7: Perform Task [ Name:Query: Word Priority:%priority Parameter 1 (%par1):Now, please tell me your favorite color. Parameter 2 (%par2): Return Value Variable:%response Stop:Off ]
A8: Flash [ Text:Color: %response Long:On ]
A9: Perform Task [ Name:Query: Line Priority:%priority Parameter 1 (%par1):Now, please speak any sentence that comes to mind. Parameter 2 (%par2): Return Value Variable:%response Stop:Off ]
A10: Flash [ Text:Sentence: %response Long:On ]


Query: Word
A1: Perform Task [ Name:Enable Response Priority:%priority Parameter 1 (%par1):Word Parameter 2 (%par2):Query: Word Return Value Variable: Stop:Off ]
A2: Variable Set [ Name:%AVPrompt To:%par1 Do Maths:Off Append:Off ]
A3: Say [ Text:%AVPrompt Engine:Voice:Default:default Stream:3 Pitch:5 Respect Audio Focus:On Network:Off Continue Task Immediately: Off ]
A4: AutoVoice Recognize [ Configuration:
Prompt Text: %AVPrompt
Voice command without headset
Command: "all" Package:com.joaomgcd.autovoice Name:AutoVoice Recognize Timeout (Seconds):120 ]
A5: If [ %avcommnofilter !Set ]
A6: Return [ Value:!Canceled! Stop:On ]
A7: End If
A8: Wait Until [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ] If [ %AVReturn Set ]
A9: Perform Task [ Name:Get Response Data Priority:%priority Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable:%return Stop:Off ]
A10: Return [ Value:%return Stop:On ]


Query: Line
A1: Perform Task [ Name:Enable Response Priority:%priority Parameter 1 (%par1):Line Parameter 2 (%par2):Query: Line Return Value Variable: Stop:Off ]
A2: Variable Set [ Name:%AVPrompt To:%par1 Do Maths:Off Append:Off ]
A3: Say [ Text:%AVPrompt Engine:Voice:Default:default Stream:3 Pitch:5 Respect Audio Focus:On Network:Off Continue Task Immediately: Off ]
A4: AutoVoice Recognize [ Configuration:
Prompt Text: %AVPrompt
Voice command without headset
Command: "all" Package:com.joaomgcd.autovoice Name:AutoVoice Recognize Timeout (Seconds):120 ]
A5: If [ %avcommnofilter !Set ]
A6: Return [ Value:!Canceled! Stop:On ]
A7: End If
A8: Wait Until [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ] If [ %AVReturn Set ]
A9: Perform Task [ Name:Get Response Data Priority:%priority Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable:%return Stop:Off ]
A10: Return [ Value:%return Stop:On ]


Query: Text
A1: Perform Task [ Name:Enable Response Priority:%priority Parameter 1 (%par1):Text Parameter 2 (%par2):Query: Text Return Value Variable: Stop:Off ]
A2: Variable Set [ Name:%AVPrompt To:%par1 Do Maths:Off Append:Off ]
A3: Say [ Text:%AVPrompt Engine:Voice:Default:default Stream:3 Pitch:5 Respect Audio Focus:On Network:Off Continue Task Immediately: Off ]
A4: AutoVoice Recognize [ Configuration:
Prompt Text: %AVPrompt
Voice command without headset
Command: "all" Package:com.joaomgcd.autovoice Name:AutoVoice Recognize Timeout (Seconds):120 ]
A5: If [ %avcommnofilter !Set ]
A6: Return [ Value:!Canceled! Stop:On ]
A7: End If
A8: Wait Until [ MS:0 Seconds:1 Minutes:0 Hours:0 Days:0 ] If [ %AVReturn Set ]
A9: Perform Task [ Name:Get Response Data Priority:%priority Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable:%return Stop:Off ]
A10: Return [ Value:%return Stop:On ]


Reset Responses
A1: Variable Set [ Name:%Response_Unrecognized To: !Disabled! Do Maths:Off Append:Off ]
A2: Variable Set [ Name:%Response_Cancel To: !Disabled! Do Maths:Off Append:Off ]
A3: Variable Set [ Name:%Response_Yes To:!Disabled! Do Maths:Off Append:Off ]
A4: Variable Set [ Name:%Response_No To:!Disabled! Do Maths:Off Append:Off ]
A5: Variable Set [ Name:%Response_Word To:!Disabled! Do Maths:Off Append:Off ]
A6: Variable Set [ Name:%Response_Line To:!Disabled! Do Maths:Off Append:Off ]
A7: Variable Set [ Name:%Response_Text To:!Disabled! Do Maths:Off Append:Off ]


Enable Response
A1: AutoVoice Set Cmd Id [ Configuration:Setting Last Command Id to "%par2" Package:com.joaomgcd.autovoice Name:AutoVoice Set Cmd Id Timeout (Seconds):0 ]
A2: Perform Task [ Name:Reset Responses Priority:%priority Parameter 1 (%par1): Parameter 2 (%par2): Return Value Variable: Stop:Off ]
A3: Variable Set [ Name:%Response_Unrecognized To:%par2 Do Maths:Off Append:Off ] If [ %par1 !~R Word & %par1 !~R Line & %par1 !~R Text ]
A4: Variable Set [ Name:%Response_Cancel To:%par2 Do Maths:Off Append:Off ] If [ %par1 !~R Word & %par1 !~R Line ]
A5: Variable Set [ Name:%Response_Yes To:%par2 Do Maths:Off Append:Off ] If [ %par1 ~R Yes ]
A6: Variable Set [ Name:%Response_No To:%par2 Do Maths:Off Append:Off ] If [ %par1 ~R No ]
A7: Variable Set [ Name:%Response_Word To:%par2 Do Maths:Off Append:Off ] If [ %par1 ~R Word ]
A8: Variable Set [ Name:%Response_Line To:%par2 Do Maths:Off Append:Off ] If [ %par1 ~R Line ]
A9: Variable Set [ Name:%Response_Text To:%par2 Do Maths:Off Append:Off ] If [ %par1 ~R Text ]


Get Response Data
A1: Variable Set [ Name:%return To:%AVReturn Do Maths:Off Append:Off ]
A2: Variable Clear [ Name:%AVReturn Pattern Matching:Off ]
A3: Return [ Value:%return Stop:On ]

nicro...@gmail.com

unread,
Jan 1, 2015, 11:14:59 PM1/1/15
to joao...@googlegroups.com, nicro...@gmail.com
A bit better still... I've now started a Tasker project tab that I've called "AutoVoice Library" and I've taken everything discussed (and a little more) and packaged it into something anyone should be able to import:

https://drive.google.com/file/d/0B_Gw3Ub2xmDTQUR4NFZlS3pSZk0/view?usp=sharing

I'm not sure if any of these will become developed enough and helpful enough to make more sense to have them within the plugin itself instead of as a collection of Tasker tasks...but it may not be all that bad of an idea.

Waqas Ahmed

unread,
Jan 2, 2015, 11:20:27 AM1/2/15
to joao...@googlegroups.com, nicro...@gmail.com
Hi Nicro,

Thank you so much for proving us an opportunity to play with your nice piece of work. I am an ordinary user of the tasker and it's plugins. I tried to understand your work and have an idea that it can be very useful but the problem is I need some kind of guidance to use these tasks for my own will.

Suppose I have a voice dial task and I ask my cell to call a numer, let's say "Ahmed". This task generates a variable %contact and autocontact search this %contact in my contacts and speak it's output which is used for further calling process. Sometimes autovoice can't recognize what I say, or misunderstands which may results in inaccurate results.

I want to implement your method in this task to correct all problems. Can you help me out?

This is just an example to understand your work. Thanks in advance

nicro...@gmail.com

unread,
Jan 2, 2015, 1:42:45 PM1/2/15
to joao...@googlegroups.com, nicro...@gmail.com
Hi Amhed,

Since you're replying to the first message of the thread, I'm not sure if you've seen the most recent developments or not. In my previous post I added a link to a file on Google Drive. This file can be downloaded to your Android device and imported into Tasker. When you do that, you should get a new Project tab called "AutoVoice Library", and in the tasks within, there is one called "AutoVoice Library Example" that has a few simple example use cases that might help get you going.

As for your specific issue... If the voice input is not correctly recognizing what you say, there's nothing in my library that will really help. From what I understand though, the Google speech recognition is based more around conversational language, so single words being recognized accurately might be problematic. The more language you can allow for in the response, the better for the Google recognition.

One way I have found to make this work, is to use the ability for AutoVoice to create regex variables in the recognition profile. So, if you are having a task prompt you at every step of the way asking for single word responses, recognition might suffer...but if you can instead roll many of those steps together into a more natural language, it should improve.

(Just in case, here's some info on regex capture groups: http://www.rexegg.com/regex-capture.html#namedgroups On top of that, https://www.debuggex.com/ is a great resource for helping debug regex for purposes like this too...just make sure to change the regex engine away from JavaScript over to PCRE so it will function as it does in Tasker.)

For example... If you're trying a profile to recognize "call" and then within that task you're having it ask you again for the name of the contact, I would reorganize this so that my "call" profile had a regex like this at least:

call (?<person>.*)

This will require that you say something after the word "call" (like "call Ahmed"), but if kept simple like this, you can also still say anything before "call" as well and still have it recognize. This regex would still also work if you say something much longer, so long as it ends with "call <person>". So this should work still too:

"That's enough of the weather for now, but let's go ahead and call Ahmed".

The more you say before the word "call", the better the Google voice recognition should be (in theory) since it has more context to build from.

Now, all of that said... I have a simple AutoContacts Library as well, and my tasks have a special return case for when a contact isn't found. I call this task to find my contact and check the return variable for either the data I need, or a value of "!Not Found!". In the parent task that calls my AutoContacts task, I then check the return variable for this "!Not Found!" and I have the task loop up to ask for the contact name again so the process of collecting the name of the contact can begin again.

Hopefully a combination of longer spoken input and smart retrying can get you what you need, but if you'd like to share your specific task that you're having trouble with also, maybe we can provide some more specific help too. These suggestions will probably work in many situations but not always.

Waqas Ahmed

unread,
Jan 3, 2015, 8:03:34 AM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
I suspect I failed to explain the matter in a good way. 

I have a very simple autocontact task. It just react my autovoice call phrase to find the contact and call that number.

I want that when I say call phrase, It should find that name in my contact and reply me with the name it finds, if It finds more than one number or different types of numbers like home or work or mobile etc., it should ask me to dial what ever I want.

How can I use your double check mechanism? I'll try to send that task to you soon


On Wednesday, 6 August 2014 02:00:57 UTC+5, nicro...@gmail.com wrote:

dmoney

unread,
Jan 3, 2015, 10:27:34 AM1/3/15
to joao...@googlegroups.com
Looks cool.

How does one use the project?

dmoney

unread,
Jan 3, 2015, 12:10:33 PM1/3/15
to joao...@googlegroups.com
Ah, i found the test task.

Seems to work except the task doesn't seem to quit when i say "done"

nicro...@gmail.com

unread,
Jan 3, 2015, 2:38:30 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
I also suspect that this is a project complex enough for some documentation...so my apologies if things aren't as clear as they could be (yet). I'll see about fixing this soon, with at least some basic info so it will be easier to navigate. I'll let you guys all know when this happens.

For anything more complex than the "AVL: Ask For..." functions, it may involve creating additional responses, but I think your task in particular may not need that...lets see what we can do...

First, create a profile. AutoVoice Recognize, command: "send(?: a|an)? email to (?<person>.*)" (regex) Have this profile trigger a new "Send Email" task.

The "Send Email" task, when called invoked through that profile, should have all of the standard variables, plus a %person variable that should contain a string with the name of the contact. In pseudo-code, it should probably look something like this:

1. if %person !Set
2. AVL: Ask For Line, par1="Who would you like to send en email to?", return value: %person
3. Stop, if %person eq "!Canceled!"
4. End If
5. AutoContacts, Contact Name or Nickname: %person, Name as Nickname: true
6. if %acid !Set
7. AVL: Say, par1="Sorry, I couldn't find a '%person' in your contact list."
8. Variable Clear: %person
9. Goto Line 1
10. End If

This is a basic example, but the idea should be here, I think. Since you're just grabbing a data field (like a name), you'll have to do the verification of the input yourself...there's just no way for the library to know how it needs to be used in each custom situation. Though, the library should help to dramatically standardize responses so the checking you have to do yourself should be reduced to a near minimum (I hope). As I mentioned before too, I also have an AutoContacts library that contains a task specifically for the AutoContacts portion of this script too. Creating "function" tasks to reduce 5 or 6 lines into 2 or 3 has been a huge help in creating more complex scripts...if for nothing else, because readability and reorganization become tremendously easier.

My version of the library is broken due to some new additions, otherwise I'd upload some of the changes (more examples and more helper functions could possibly help in cases like this). When I do get those resolved, I'll try to upload the new version with some level of documentation.

nicro...@gmail.com

unread,
Jan 3, 2015, 2:42:38 PM1/3/15
to joao...@googlegroups.com
The "done" command probably only works during the portion of that example where it's grabbing a block of text from the user. In almost all other instances, saying "cancel" instead (or manually pressing the microphone button on-screen) should stop the example task.

What is active and what isn't is controlled per-task. The "AVL: Ask For..." functions can serve as a model for creating anything that requires more complex responses. As I was mentioning to Ahmed though, I will make an effort to create some documentation to come along with the next changes (hopefully within the week).

nicro...@gmail.com

unread,
Jan 3, 2015, 4:43:50 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
Actually...I went ahead and cranked some of the more important info out into a doc. It's got some info in related to the newer changes I've been working on, but it should cover most of the basics and hopefully provide a little bit of a foot-hold until I can put more in it and get you guys the latest additions.

https://docs.google.com/document/d/1YJ9SU0d6-TWilEj0s0OjnTDwww_pS4t6Cr0zWT4Ane0/edit?usp=sharing

dmoney

unread,
Jan 3, 2015, 8:38:22 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
This is really cool.

Thanks very much for the work your doing. It gives some good ideas about how to structure my other tasker tasks and autvoice stuff as well!

dmoney

unread,
Jan 3, 2015, 8:56:00 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com

FYI - I noticed when go to tasker now i get an error some errors related to this project:


On Saturday, January 3, 2015 3:43:50 PM UTC-6, nicro...@gmail.com wrote:

nicro...@gmail.com

unread,
Jan 3, 2015, 9:03:05 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
Ah ha, sorry about that. I think I see what I need to do to fix it (add a '?:' to the regex group to explicitly make it unnamed...I think), but I'm not sure why I haven't had any errors related to it on my side.

I'm actually making a bit more progress on some of the other things that I wanted to fix...so much that they don't appear to be broken anymore. I'm going to finish up some testing and then I'll post a new link with a new library version for you guys that should hopefully include a fix for your errors too. More on that in just a short while, I hope...


On Saturday, January 3, 2015 5:56:00 PM UTC-8, dmoney wrote:
> FYI - I noticed when go to tasker now i get an error some errors related to this project:
>
>
>
>
>

nicro...@gmail.com

unread,
Jan 3, 2015, 9:26:51 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
https://drive.google.com/folderview?id=0B_Gw3Ub2xmDTVWdTcU5kcS1qSUE&usp=sharing

This link should be a bit more permanent. It's now to a directory instead of directly to a file. The top level will always have the latest, and I'll move old versions into the (surprise!) "Old Versions" directory.

The new version has a couple of good additions...

The most important addition is the addition of the Assistance Request profile. All AVL communication should be initiated by running the associated "AVL: Assistance Request" task. If you reset your app preferences, you can select Tasker as the program to answer Assistance Request hints to make it easier to call, or you can simply make an icon and launch it from there.

The most notable is the introduction of grabbing contextual information from verbal responses. Now, if I enable a special response called "Context", several profiles will be enabled that will attempt to populate variables set aside for general context information (like time, date, etc.). With this, it should be possible to create a "New Appointment" task, and anywhere around the actual command to create this new appointment, you could also say the time for the appointment anywhere in the phrase with the command, and it should be able to still pull the proper information. There are no real examples for this available yet...but you can review the "Info:" prefixed profiles to get a general idea.

There's now an "AVL: Confirm" task, that acts like the "AVL: Ask For..." tasks, except it only accepts a yes/no response. This was simply neglected in the last version.

I've also added a bit of commentary to the example task, and I've given it a simple profile so it can be called by saying the command "example".


Try it out and let me know how things go. I'll go touch the documentation again to make note of a few differences since I wrote it earlier, but that should be mostly current now too.

nicro...@gmail.com

unread,
Jan 3, 2015, 11:13:43 PM1/3/15
to joao...@googlegroups.com, nicro...@gmail.com
I just uploaded version 0.1.1 to fix a problem with the Assistance Request task clashing in some situations (like after matching any other non-AVL AutoVoice task). This was causing all attempts to use AVL: Assistance Request to fail silently after the problem arose. If the recognition suddenly stops working, disable and re-enable Tasker, and update to this new version of the library.

Marta Hintz

unread,
Jan 4, 2015, 11:11:27 AM1/4/15
to joao...@googlegroups.com
Wow, this is awesome stuff. Thanks for the share and the great info that accompanies it.

Marta Hintz

unread,
Jan 15, 2015, 9:48:31 PM1/15/15
to joao...@googlegroups.com
I am really trying to use this, but I think I need more complete examples - the examples here are good, but I need just one that is complete. I am getting mixed up with the 3 in one task example.   Is that possible?  I would be so very grateful!  I am trying to use some of my already completed task to use in this system.  It takes me to re-write the task, but that is good, NP - but then I get lost.     

nicro...@gmail.com

unread,
Jan 15, 2015, 10:21:22 PM1/15/15
to joao...@googlegroups.com
On Thursday, January 15, 2015 at 6:48:31 PM UTC-8, Marta Hintz wrote:
> I am really trying to use this, but I think I need more complete examples - the examples here are good, but I need just one that is complete. I am getting mixed up with the 3 in one task example.   Is that possible?  I would be so very grateful!  I am trying to use some of my already completed task to use in this system.  It takes me to re-write the task, but that is good, NP - but then I get lost.     
>
> On Sunday, January 4, 2015 at 8:11:27 AM UTC-8, Marta Hintz wrote:Wow, this is awesome stuff. Thanks for the share and the great info that accompanies it.  


Hi Marta,

If you'd like to share the problem you're trying to solve, I'll work through a solution with you. The more detailed you can be, the better. It may also help us generate a better, more real-world example to make it easier for others to understand too.

The example task has just a few basic ways to get input from the user (a single word, a full sentence [the most common], or multiple lines of text). The idea is to use these tasks to get that input from the user like a function in a programming language...but it's still up to you to decide exactly how to use that input. It's just taking the very common things that have to be done each time, and it's putting them into one place so they don't have to be done separately in each and every task you want to use them.

Also, a few responses exist, but there are probably many more that might helpful that I may not have included yet. It could be that the best solution to your problem might involve adding something here, and I haven't written anything about that really. The tasks could be dissected and studied, of course, but it may not be immediately clear. However, if this is the case, I can definitely help with this too.

nicro...@gmail.com

unread,
Jan 27, 2015, 10:23:22 PM1/27/15
to joao...@googlegroups.com
Hi again Marta,

I just recently upgraded to Lollipop (5.0.1) from Kitkat (4.4.4), and I've had to make some modifications to the library to make things work. It looks like the changes to silent mode broke the method I was using to check to see if it would respond verbally or through a Flash action. There were a couple of other minor things I've touched up related to the upgrade as well since they also weren't working quite right. I'm not entirely sure, but this could be why you were having trouble with this before.

Hopefully within the next week or two I'll be able to do a more thorough functionality test and when I'm done I'll upload a new version that should be a bit more Lollipop-friendly.

Sorry for not mentioning anything about Android version or anything before (especially if it caused any frustration on your end!)...I didn't really think it would be too much of an issue. I will start to make note of it from now on though, possibly along with Tasker and AutoVoice versions as well.


On Thursday, January 15, 2015 at 6:48:31 PM UTC-8, Marta Hintz wrote:

easiuser

unread,
Jan 28, 2015, 2:58:03 PM1/28/15
to joao...@googlegroups.com, nicro...@gmail.com
It looks like you have put a lot of thought and time into this.  Thank you for that.  As most Tasker users, I am used to customizing everything and can't find a voice assistant that does everything I want.  At one time I thought "Utter" might be it.

One thing that is not clear is the use of "@Var" 

I understand that you are replacing @Var with whatever is passed in %par2 but I fail to see the benefit.  The calling routine could just as easily put the replacement text or variable in %par1 inside the perform task action.

I am probably missing something obvious. :/

Thanks.

nicro...@gmail.com

unread,
Jan 28, 2015, 8:32:16 PM1/28/15
to joao...@googlegroups.com, nicro...@gmail.com
The "@Var" was kind of a hold-over legacy from some work on my own voice assistant, and it stayed because I simply couldn't think of a more beneficial %par2 for the task. (I'm definitely open to suggestions though!)

The reason this exists, is because I was using a "Speech Table" that contained various announcement-style texts within. In some cases it just made more sense to have a placeholder variable that wasn't parsed by Tasker. This let me have a single announcement, like "Wifi connected to @Var", or "Sorry, but I can't find a @Var in your contact list" in my speech table instead of multiple entries, or instead of having to manually concatenate in each task that may use this kind of response.

The reason I had speech tables to begin with was to allow for customizable personalities to a voice assistant or other similar features. It really has nothing specific to AutoVoice itself and since all of the other voice parameters are stored in variables, there wasn't anything else very obvious to take its place.

Marta Hintz

unread,
Jan 29, 2015, 10:13:29 PM1/29/15
to joao...@googlegroups.com
Look forward to your updates thanks! I think this is definitely the mode I want to build my tasks with, especially with autovoice.
Reply all
Reply to author
Forward
0 new messages