使用 Dragonfly CompoundRule 时重复额外的操作
Repeating an extra when using a Dragonfly CompoundRule
使用语音命令框架dragonfly2,您可以编写如下语法:
chrome_rules = MappingRule(
name='chrome',
mapping={
'down [<n>]': actions.Key('space:%(n)d'),
},
extras=[
IntegerRef("n", 1, 100)
],
defaults={
"n": 1
}
)
这让我按 space n
次,其中 n
是某个整数。但是如果我想在同一个语法中多次使用同一个变量(n
),我该怎么办?如果我在语法中重复它,例如'down <n> <n>'
然后说类似 "down three four" 的东西,Dragonfly 会正确解析它,但它只会执行 actions.Key('space:%(n)d')
和 n=3
,使用 n
的第一个值.我怎样才能让它执行 3 次,然后使用同一个变量执行 4 次?
理想情况下,我不想在 extras 和 defaults 中复制变量 n
,因为这看起来像是冗余代码。
TL;DR:你的MappingRule
以字典的形式将数据传递给你的Action
(例如Key
,Text
),所以它只能通过每增加一个价值。你现在最好的选择可能是创建多个附加功能。
这是蜻蜓解析识别方式的副作用。我会先用 Action
个对象来解释它,然后我们可以分解为什么会在 Rule
级别发生这种情况。
当 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",
}
看到问题了吗?这意味着我们只能为每个 extra 传递一个值。即使我们组合多个动作,我们也会遇到同样的问题。例如:
{
"down <n> <n>": Key("%(n)d") + Text("%(n)d"),
}
在幕后,这两个动作组合成一个 ActionSeries
对象 - 一个动作。它公开了相同的 execute
接口。一系列动作,一个data
dict.
请注意,复合规则不会发生这种情况,即使每个基础规则共享一个具有相同名称的额外规则。那是因为 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 尝试为每个 extra 提取一个值,并获得第一个值。然后,它将该值填充到字典中并将其向下传递给 Action
。其他事件丢失。
使用语音命令框架dragonfly2,您可以编写如下语法:
chrome_rules = MappingRule(
name='chrome',
mapping={
'down [<n>]': actions.Key('space:%(n)d'),
},
extras=[
IntegerRef("n", 1, 100)
],
defaults={
"n": 1
}
)
这让我按 space n
次,其中 n
是某个整数。但是如果我想在同一个语法中多次使用同一个变量(n
),我该怎么办?如果我在语法中重复它,例如'down <n> <n>'
然后说类似 "down three four" 的东西,Dragonfly 会正确解析它,但它只会执行 actions.Key('space:%(n)d')
和 n=3
,使用 n
的第一个值.我怎样才能让它执行 3 次,然后使用同一个变量执行 4 次?
理想情况下,我不想在 extras 和 defaults 中复制变量 n
,因为这看起来像是冗余代码。
TL;DR:你的MappingRule
以字典的形式将数据传递给你的Action
(例如Key
,Text
),所以它只能通过每增加一个价值。你现在最好的选择可能是创建多个附加功能。
这是蜻蜓解析识别方式的副作用。我会先用 Action
个对象来解释它,然后我们可以分解为什么会在 Rule
级别发生这种情况。
当 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",
}
看到问题了吗?这意味着我们只能为每个 extra 传递一个值。即使我们组合多个动作,我们也会遇到同样的问题。例如:
{
"down <n> <n>": Key("%(n)d") + Text("%(n)d"),
}
在幕后,这两个动作组合成一个 ActionSeries
对象 - 一个动作。它公开了相同的 execute
接口。一系列动作,一个data
dict.
请注意,复合规则不会发生这种情况,即使每个基础规则共享一个具有相同名称的额外规则。那是因为 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 尝试为每个 extra 提取一个值,并获得第一个值。然后,它将该值填充到字典中并将其向下传递给 Action
。其他事件丢失。