Using dragonfly2, the voice command framework, you can make a grammar like so:
chrome_rules = MappingRule(
name='chrome',
mapping={
'down [<n>]': actions.Key('space:%(n)d'),
},
extras=[
IntegerRef("n", 1, 100)
],
defaults={
"n": 1
}
)
This lets me press space n
times, where n
is some integer. But what do I do if I want to use the same variable (n
), multiple times in the same grammar? If I repeat it in the grammar, e.g. 'down <n> <n>'
and then say something like "down three four", Dragonfly will parse it correctly, but it will only execute the actions.Key('space:%(n)d')
with n=3
, using the first value of n
. How can I get it to execute it 3 times, and then 4 times using the same variable?
Ideally I don't want to have to duplicate the variable n
, in the extras and defaults, because that seems like redundant code.
TL;DR: Your
MappingRule
passes data to yourAction
(e.g.Key
,Text
) in the form of a dictionary, so it can only pass one value per extra. Your best bet right now is probably to create multiple extras.This is a side-effect of the way dragonfly parses recognitions. I'll explain it first with
Action
objects, then we can break down why this happens at theRule
level.When Dragonfly receives a recognition, it has to deconstruct it and extract any extras that occurred. The speech recognition engine itself has no trouble with multiple occurrances of the same extra, and it does pass that data to dragonfly, but dragonfly loses that information.
All
Action
objects are derived fromActionBase
, and this is the method dragonfly calls when it wants to execute anAction
:This is how
Text
works, same withKey
. It's not documented here, butdata
is a dictionary of extras mapped to values. For example:See the issue? That means we can only communicate a single value per extra. Even if we combine multiple actions, we have the same problem. For example:
Under the hood, these two actions are combined into an
ActionSeries
object - a single action. It exposes the sameexecute
interface. One series of actions, onedata
dict.Note that this doesn't happen with compound rules, even if each underlying rule shares an extra with the same name. That's because
data
is decoded & passed per-rule. Each rule passes a differentdata
dict to theAction
it wishes to execute.If you're curious where we lose the second extra, we can navigate up the call chain.
Each rule has a
process_recognition
method. This is the method that's called when a recognition occurs. It takes the current rule'snode
and processes it. Thisnode
might be a tree of rules, or it could be something lower-level, like anAction
. Let's look at the implementation inMappingRule
:I'm going to skip some complexity - the
extras
variable you see here is an early form of thedata
dictionary. See where we lose the value?Which looks like:
So, you see the issue. Dragonfly tries to extract one value for each extra, and it gets the first one. Then, it stuffs that value into a dictionary and passes it down to
Action
. Additional occurrences are lost.