2

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.

4

1 回答 1

1

TL;DR:您以字典的形式MappingRule将数据传递给您的Action(例如KeyText),因此每次额外只能传递一个值。您现在最好的选择可能是创建多个附加功能。


这是蜻蜓解析识别的方式的副作用。我将首先用Action对象来解释它,然后我们可以分解为什么会在Rule关卡中发生这种情况。

当 Dragonfly 收到识别时,它必须解构它并提取发生的任何额外内容。语音识别引擎本身对多次出现相同的extra没有问题,它确实将数据传递给dragonfly,但dragonfly会丢失该信息。

所有Action对象都派生自ActionBase,这是蜻蜓想要执行时调用的方法Action

    def execute(self, data=None):
        self._log_exec.debug("Executing action: %s (%s)" % (self, data))
        try:
            if self._execute(data) == False:
                raise ActionError(str(self))
        except ActionError as e:
            self._log_exec.error("Execution failed: %s" % e)
            return False
        return True

这就是Text工作原理,与Key. 这里没有记录,但data它是映射到值的附加字典。例如:

{
    "n":    "3",
    "text": "some recognized dictation",
}

看到问题了吗?这意味着我们只能传达每个额外的单个值。即使我们结合多个动作,我们也会遇到同样的问题。例如:

{
    "down <n> <n>": Key("%(n)d") + Text("%(n)d"),
}

在引擎盖下,这两个动作组合成一个ActionSeries对象 - 一个动作。它公开了相同的execute接口。一系列动作,一个data命令。

请注意,复合规则不会发生这种情况,即使每个基础规则共享一个具有相同名称的额外规则。那是因为data被解码并通过per-rule。每个规则将不同的data字典传递给Action它希望执行的。


如果您对我们失去第二个额外的地方感到好奇,我们可以在调用链上导航。

每个规则都有一个process_recognition方法。这是发生识别时调用的方法。它采用当前规则node并对其进行处理。这node可能是一棵规则树,也可能是较低级别的东西,例如Action. 让我们看一下中的实现MappingRule

    def process_recognition(self, node):
        """
            Process a recognition of this rule.

            This method is called by the containing Grammar when this
            rule is recognized.  This method collects information about
            the recognition and then calls *self._process_recognition*.

            - *node* -- The root node of the recognition parse tree.
        """
        # Prepare *extras* dict for passing to _process_recognition().
        extras = {
                  "_grammar":  self.grammar,
                  "_rule":     self,
                  "_node":     node,
                 }
        extras.update(self._defaults)
        for name, element in self._extras.items():
            extra_node = node.get_child_by_name(name, shallow=True)
            if extra_node:
                extras[name] = extra_node.value()
            elif element.has_default():
                extras[name] = element.default

        # Call the method to do the actual processing.
        self._process_recognition(node, extras)

我将跳过一些复杂性 -extras您在此处看到的变量是data字典的早期形式。看看我们在哪里失去了价值?

extra_node = node.get_child_by_name(name, shallow=True)

看起来像:

    def get_child_by_name(self, name, shallow=False):
        """Get one node below this node with the given name."""
        for child in self.children:
            if child.name:
                if child.name == name:
                    return child
                if shallow:
                    # If shallow, don't look past named children.
                    continue
            match = child.get_child_by_name(name, shallow)
            if match:
                return match
        return None

所以,你看到了这个问题。Dragonfly 尝试为每个额外的值提取一个值,它得到第一个值。然后,它将该值填充到字典中并将其传递给Action. 其他事件丢失。

于 2019-10-03T14:49:44.273 回答