处理动作#
介绍#
您已经在 事件生成与匹配 部分中了解了如何处理事件。现在我们将介绍动作,这将使您能够更好地管理事件及其时间依赖性。
重要提示
动作定义
<ActionName>[(param=<value>[, param=<value>]…)]
示例
# Bot utterance action
UtteranceBotAction(script="Hello", intensity=1.0)
# Bot gesture action
GestureBotAction(gesture="Wave with one hand")
动作使用 Pascal 命名风格,如事件,但以 Action
结尾。
与事件不同,动作的生命周期取决于底层事件。所有动作都包含以下主要事件,其中我们使用 X 作为动作名称的占位符
StartXAction(**action_arguments) # Start of an action with given action specific arguments
StopXAction(action_uid: str) # Stop of an action with the related uid
XActionStarted(action_uid: str) # Event to signal the action has started
XActionFinished(action_uid: str, is_success: bool, was_stopped: bool, **action_arguments) # Event to signal that the action has ended
在 Colang 中,动作就像 Python 中的对象,事件可以像动作的对象方法一样访问。
XAction(**action_arguments).Start()
XAction.Stop(action_uid: str)
XAction.Started(action_uid: str)
XAction.Finished(action_uid: str, is_success: bool, was_stopped: bool, **action_arguments)
以下是动作的两个常见生命周期,它们取决于事件
XAction.Start() -> Action state: `Starting`
XAction.Started() -> Action state: `Running`
XAction.Finished() -> Action state: `Finished`
XAction.Start() -> Action state: `Starting`
XAction.Started() -> Action state: `Running`
XAction.Stop() -> Action state: `Stopping`
XAction.Finished() -> Action state: `Finished`
在 UMIM 参考文档中,您将找到许多预定义的动作,这些动作应涵盖最常见的用例。让我们看一下最突出的动作之一,称为 UtteranceBotAction。此动作表示与用户通信的主要通道,例如通过语音或文本(取决于特定系统)。此动作与可以从 Bot 的角度分组为输出和输入事件的事件相关
输出事件
UtteranceBotAction(script: str).Start()
UtteranceBotAction.Stop(action_uid: str)
UtteranceBotAction.Change(action_uid: str, intensity: float)
输入事件
UtteranceBotAction.Started(action_uid: str, action_started_at: str, ...)
UtteranceBotActionScript.Updated(action_uid: str, interim_transcript: str, ...)
UtteranceBotAction.Finished(action_uid: str, final_transcript: str, ...)
注意
请注意,Colang 不仅限于从 Bot 的角度工作,还可以用于模拟用户端。在这种情况下,输出和输入分类将翻转。
虽然对于如何使用 send
或 match
关键字处理这些事件没有约束性规则,但在大多数情况下,我们将生成输出事件并匹配输入事件。例如,如果我们希望 Bot 在做手势之前先说完话,我们可以创建以下交互模式
flow main
match StartEvent()
send UtteranceBotAction(script="Hello").Start() as $event_ref
match UtteranceBotActionFinished(action_uid=$event_ref.action_uid)
send GestureBotAction(gesture="Wave").Start()
> /StartEvent
Hello
Gesture: Wave
我们看到,通过使用 Start 动作事件引用的 action_uid 属性,我们可以匹配到特定动作的 Finished 事件。这很重要,因为可能还有其他 UtteranceBotAction 在此之前完成。
启动 动作#
Colang 支持基于动作概念的几个功能,这些功能使设计交互模式更加方便。我们介绍的第一个功能是 start
语句。
重要提示
Start 语句定义
start <Action> [as $<action_ref_name>] [and|or <Action> [as $<action_ref_name>]…)]
示例
start UtteranceBotAction(script="Hello") as $bot_action_ref
flow main
start UtteranceBotAction(script="Hello") as $ref_action
match $ref_action.Finished()
start GestureBotAction(gesture="Wave")
match RestartEvent()
Hello
Gesture: Wave
关键字 start
创建一个动作对象,然后生成一个特定于动作的 Start 动作事件。可以使用 as $ref_name
存储对此动作对象的引用。有了这个动作引用,我们现在可以方便地匹配到 Finished 事件,而不再需要使用 action_uid 参数来标识特定动作。
现在让我们看一个常见用户动作 UtteranceUserAction 的示例。此动作表示 UtteranceBotAction 的对应物,并且是用户表达自己的主要通道,例如通过说话、写作或任何其他方式,具体取决于实际系统。用户动作通常不是由 Colang 启动的,而是由用户(系统)启动的。以下是最重要的动作事件和参数
UtteranceUserActionStarted(action_uid: str)
UtteranceUserActionTranscriptUpdated(action_uid: str, interim_transcript: str)
UtteranceUserActionIntensityUpdated(action_uid: str, intensity: float)
UtteranceUserActionFinished(action_uid: str, final_transcript: str)
有了这些,现在让我们构建一个小对话模式
flow main
match UtteranceUserAction.Finished(final_transcript="Hi")
start UtteranceBotAction(script="Hi there! How are you?") as $ref_action_1
match $ref_action_1.Finished()
match UtteranceUserAction.Finished(final_transcript="Good and you?")
start UtteranceBotAction(script="Great! Thanks") as $ref_action_2
start GestureBotAction(gesture="Thumbs up") as $ref_action_3
match $ref_action_2.Finished() and $ref_action_3.Finished()
> Hi
Hi there! How are you?
> Good and you?
Great! Thanks
Gesture: Thumbs up
您可能已经注意到,这与我们在介绍示例 introduction/interaction_sequence/main.co 中看到的示例非常相似。不同之处在于我们有更多的时间控制,并且仅在 Bot 完成话语后才开始匹配用户输入。另请注意,只有在第二个 Bot 话语动作和 Bot 手势动作都完成后,交互模式才完成。
等待 动作#
让我们介绍 await
语句,以进一步简化前面的示例
flow main
match UtteranceUserAction.Finished(final_transcript="Hi")
await UtteranceBotAction(script="Hi there! How are you?")
match UtteranceUserAction.Finished(final_transcript="Good and you?")
# ...
await
是启动动作并等待动作完成(即匹配 .Finished()
事件)的快捷方式表示法。
重要提示
Await 语句定义
await <Action> [as $<action_ref_name>] [and|or <Action> [as $<action_ref_name>]…)]
示例
await UtteranceBotAction(script="Hello") as $bot_action_ref
遗憾的是,我们无法使用此方法简化示例的第二部分……或者我们可以吗?实际上,是的!我们可以使用动作分组,使用 and
关键字来简化它,如下所示
flow main
match UtteranceUserAction.Finished(final_transcript="Hi")
await UtteranceBotAction(script="Hi there! How are you?")
match UtteranceUserAction.Finished(final_transcript="Good and you?")
await UtteranceBotAction(script="Great! Thanks") and GestureBotAction(gesture="Thumbs up")
动作分组与事件分组相同,使用关键字 start
和 await
而不是 send
和 match
。
重要提示
请注意,这
await Action1() or Action2()
将随机仅启动其中一个动作(而不是两个!)并等待其完成
为了进一步简化,我们实际上可以完全省略所有 await
关键字,因为它是默认语句关键字。
flow main
match UtteranceUserAction.Finished(final_transcript="Hi")
UtteranceBotAction(script="Hi there! How are you?")
match UtteranceUserAction.Finished(final_transcript="Good and you?")
UtteranceBotAction(script="Great! Thanks") and GestureBotAction(gesture="Thumbs up")
重要提示
await
是默认语句关键字,可以省略。
如果我们想启动两个动作,并且只等到其中一个动作完成后,我们可以这样实现
flow main
match StartEvent()
start UtteranceBotAction(script="Great! Thanks") as $ref_action_1
and GestureBotAction(gesture="Thumbs up") as $ref_action_2
match $ref_action_1.Finished() or $ref_action_2.Finished()
关于动作的更多信息#
如果需要,我们还可以使用其引用停止动作,如下所示
flow main
match StartEvent()
start UtteranceBotAction(script="Great! Thanks") as $ref_action
send $ref_action.Stop()
遗憾的是,使用简单的聊天 CLI,我们将看不到 Stop 事件的任何效果,因为话语立即完成。但在任何真实系统中,话语都需要一些时间才能完成,并且可以在需要时像这样停止。
另一个需要指出的细节是通过动作引用访问的动作事件与直接通过动作匹配之间的区别
# Case 1) Wait for Finished event of the specific action
start UtteranceBotAction(script="hi") as $action_ref
match $action_ref.Finished()
# Case 2) Wait for the Finished event of any UtteranceBotAction
match UtteranceBotAction.Finished()
在第一种情况下,匹配是针对特定的动作引用(相同的 action_uid 参数),并且不会匹配到任何其他 UtteranceBotAction 的 Finished 事件。第二种情况更通用,将匹配来自任何 UtteranceBotAction 的任何 Finished 事件。
有了这些,我们现在准备好在下一章 定义流 中了解有关流概念的更多信息。