对话流程
了解语音输入、播放状态、转写事件、动作队列执行、叙事触发以及中断处理。
在会话建立后,玩家组件会转发音频或文本输入,Convai 返回转录内容和角色输出,而 chatbot 组件会播放音频、更新面部和情绪数据,并排队动作。了解当前 SDK 中哪些部分是事件驱动的,以及哪些辅助函数是可靠的,有助于 Blueprint 在不依赖不受支持的状态假设的情况下驱动 UI 和游戏玩法。
播放与辅助状态
UConvaiChatbotComponent 提供若干 BlueprintPure 状态和播放辅助函数:
GetIsTalking
正在说话
返回组件当前的音频播放标志。可用于字幕时机、动画过渡和中断按钮。
GetTalkingTimeElapsed
—
返回当前音频响应的已播放时间。
GetTalkingTimeRemaining
—
返回估计的剩余播放时间。
IsListening
Is Listening
存在于 Blueprint API 中,但当前返回 false 在 SDK 源码中。
IsProcessing
正在思考
存在于 Blueprint API 中,但当前返回 false 在 SDK 源码中。
IsInConversation
Is In Conversation
组合这些辅助状态。因为 IsListening 和 IsProcessing 当前返回 false,所以这实际上在 GetIsTalking 于当前 SDK 中绑定。
对于当前版本,请将 GetIsTalking、音频播放委托、转录事件和动作事件视为可靠的运行时信号。在 SDK 实现发生变化之前,不要围绕 IsListening 或 IsProcessing 构建关键 UI 逻辑。
上图展示了概念上的理想流程。它并不是当前 SDK 中所有辅助函数的一一对应映射。
语音输入模式
UConvaiPlayerComponent 支持两种模式来控制何时将音频转发给 Convai。
按住说话
在按住说话模式下,游戏逻辑会显式打开和关闭音频流。请在玩家开始说话时调用 UnmuteStreamingAudio 在 UConvaiPlayerComponent ,并在 MuteStreamingAudio 时调用。玩家组件仅在打开窗口期间转发音频。
在存在环境噪音的训练模拟中使用按住说话——如机器声、教室环境音或多个同处一地的用户——因为自动语音检测可能会产生错误的句尾截断。
语音活动检测
可通过在玩家组件上调用 UpdateVadBP(bool EnableVAD)来切换语音活动检测(VAD)。详细的 VAD 阈值位于 FConvaiVADSettings 中的 Convai 项目设置对象上,可通过实用设置函数读取或修改。
bUseServerDefault
bool
true
当 true时,下面所有按字段设置的值都会被忽略,Convai 将应用其默认值。设置为 false 以覆盖单独字段。
Confidence
float
0.7
帧中包含语音的最低 VAD 模型概率。提高该值可减少背景噪音造成的误报;如果角色漏掉了轻声说话者,则降低该值。
StartSecs
float
0.2
在触发“用户开始说话”事件之前持续语音的秒数。更高的值会忽略短暂的语音片段。
StopSecs
float
2.2
VAD 到达终点前的静音秒数。更低的值会更快检测到句尾,但代价是可能截断语速较慢的说话者。
MinVolume
float
0.6
归一化振幅下限,低于该值的音频会被视为静音。提高该值可拒绝较轻的背景声音。
VAD 适用于免手操作或移动场景,在这些场景中按住说话按钮并不现实。
转录
转录通过 OnTranscriptionReceivedDelegate公开, BlueprintAssignable 委托,位于 UConvaiConversationComponent (由 chatbot 和 player 组件共同继承)。该子系统会将用户转录内容转发到玩家会话,并将机器人转录内容转发到 chatbot 会话。
委托参数如下:
Speaker
UConvaiConversationComponent*
广播该转录事件的组件。当前广播位置传入 this.
Listener
UConvaiConversationComponent*
在委托签名中存在。当前广播位置传入 nullptr.
转录
FString
此时该发言中的转录文本。
IsTranscriptionReady
bool
当前转录路径中的就绪标记。机器人的转录文本通过 true转发;用户转录文本可能以 false到达,随后再以空的最终标记 true.
IsFinal
bool
true 表示这是该发言的最终更新。
当你需要用户发言转录时,绑定到玩家组件。当你需要机器人回复转录时,绑定到 chatbot 组件。对于用户字幕,请显示非空的 转录 载荷,而不是只根据 IsTranscriptionReady.
文本输入
玩家也可以发送文本而不是音频。 UConvaiPlayerComponent::SendText 接收一个目标 UConvaiConversationComponent 参数和一个 FString,但当前实现会将文本作为 user_text_message 通过子系统发送,并且不会使用目标参数进行路由。它也不会直接广播 OnTranscriptionReceivedDelegate 与提交的文本。可将此路径用于无障碍输入、训练模拟中由主持人控制的覆盖输入,以及注入脚本化对话且不使用麦克风输入的自动化测试框架。
动作队列执行
当 Convai 返回包含角色动作的响应时, OnActionReceivedEvent_V2 会触发,并且该序列会被添加到 ActionsQueue中。如果队列为空,新序列会成为队列。如果队列中已经包含一个动作,则当前第一个动作会被保留,而新序列会替换剩余的排队项。
Blueprint 中标准的队列驱动执行模式:
绑定到
OnActionReceivedEvent_V2在BeginPlay.当事件触发时,调用
FetchFirstAction以读取队列中的第一个FConvaiResultAction。在你的游戏逻辑中执行该动作(移动到某个位置、播放动画、打开门等)。
调用
HandleActionCompletion(true)在成功时调用调用
HandleActionCompletion(false)在失败时调用。Convai 会收到通知,并可能生成恢复响应。如果某个动作发生无法恢复的失败——例如目标 Actor 不再存在——请调用
AbortActionSequence以丢弃队列中所有剩余动作。
该 bWaitForBotSpeech 动作模板上的标志会门控 StartFirstAction ,用于新到达序列中的第一个动作。该门控可在机器人开始说话、机器人说话结束、响应没有机器人音频,或等待计时器到期时释放。后续队列推进由 HandleActionCompletion.
中断
InterruptSpeech 在 UConvaiChatbotComponent 通过在 InVoiceFadeOutDuration 秒内淡出音频,来停止角色当前的播放。淡出时长也可通过组件上的默认 InterruptVoiceFadeOutDuration 属性进行配置。
该类还公开了 Broadcast_InterruptSpeech 作为一个 NetMulticast Reliable RPC,用于全网络范围的中断路径。 InterruptSpeech 本身会在调用它的组件上应用淡出请求。
该 OnInterruptedEvent 委托会在聊天机器人正在说话或处理中应用中断时触发。当前实现会广播聊天机器人组件并传入 nullptr 适用于玩家组件。
插件支持渐进式淡出而不是瞬时切断的原因在于,突兀的音频停止会产生感知伪影。淡出时长让设计师可以控制中断听起来是自然还是突兀。
调用语音和叙事触发器
两个 BlueprintCallable 这些函数让 Blueprint 可以在没有玩家输入的情况下驱动角色说话:
ExecuteNarrativeTrigger(Blueprint 显示名称 Invoke Speech)——将提供的文本作为动态上下文事件添加,并使用EC_RunLLMOption::Always。Blueprint 节点标记为 Invoke Speech;C++ 名称ExecuteNarrativeTrigger仅在代码中可见。InvokeNarrativeDesignTrigger(Blueprint 显示名称 Invoke Narrative Design Trigger)——通过 chatbot 组件排队或调用一个命名的 Narrative Design 触发器。
使用 ExecuteNarrativeTrigger 适用于一次性、自由形式的提示,其精确措辞可在运行时变化。当触发器名称是与 Narrative Design 约定好的稳定契约时,请使用 InvokeNarrativeDesignTrigger 。
这两个函数都在 Blueprint API 中公开了 InGenerateActions 和 InReplicateOnNetwork 参数。在当前实现中, ExecuteNarrativeTrigger 通过 AddContextEvent 进行路由,并且不使用这两个参数。 InvokeNarrativeDesignTrigger 使用内部触发器路径,并在会话建立之前将断开的触发调用排队。
使用示例
按住说话进行角色交互
一个医学训练模拟,学习者通过按住按钮与患者角色对话。
绑定一个 Pressed 事件到交互输入动作,以 Unmute Streaming Audio 调用在玩家组件上——这会打开音频流。
绑定 Released 事件到 Mute Streaming Audio ——这会关闭音频流。
从输入事件中跟踪你自己的录音指示器。使用
GetIsTalking和音频播放委托,在角色响应播放时显示字幕或说话指示器。
预期结果:患者角色只会在玩家按住按钮时接收音频。响应播放指示器会跟随 GetIsTalking 或播放委托。
主持人文本注入
一个训练模拟场景,主持人可以输入一条消息,让 AI 角色接收并回应,而无需使用麦克风。
在编辑器内或运行时构建一个简单的 UI 小部件,包含一个文本字段和一个 发送 按钮。
将 发送 按钮的 On Clicked 事件到 Send Text 连到玩家组件,并将文本字段的内容作为输入字符串传入。
预期结果:玩家组件会通过子系统将输入的消息作为文本输入发送。如果你需要为主持人消息显示本地字幕,可从你的 UI 状态中显示已提交的文本。
故障排查
输入后角色没有开始说话
会话未连接、音频未发送,或者文本消息未提交
检查 GetChatbotConnectionState,确认玩家组件已初始化,并验证你的输入事件是否调用了 MuteStreamingAudio 或 SendText.
GetIsTalking 变为 true ,在第一段音频响应播放时。
录音指示器从不关闭
UI 绑定到了 IsListening,而该函数当前返回 false
请根据输入的按下/释放事件来驱动录音 UI,而不是依赖 IsListening.
该指示器会完全跟随按钮状态。
动作已到达 OnActionReceivedEvent_V2 但没有执行任何操作
FetchFirstAction 未在事件处理器内部调用,或者 HandleActionCompletion 未在每次动作执行后调用
调用 Fetch First Action 在 On Actions Received 处理器。执行动作后,务必调用 Handle Action Completion 与 true 在成功时调用,或 false 失败时。
一个 打印字符串 在获取到的动作名称上调用,以确认已接收。每次完成调用后,序列中的下一个动作就会变为可用。
InterruptSpeech 没有明显效果
在 GetIsTalking 为 false 期间调用——没有音频在播放
用一个 Get Is Talking 检查来保护该调用。仅在角色处于说话状态时调用 InterruptSpeech 。
GetIsTalking 返回 false 在淡出完成后。
相关概念
会话生命周期事件系统最后更新于
这有帮助吗?