消息传递机制
在工作流执行期间(或当执行队列状态发生变化时),PromptExecutor 会
通过 PromptServer 实例的 send_sync 方法向客户端回传消息。
这些消息由 api.js 文件中定义的 socket 事件监听器负责接收(截至本文撰写时,该监听器大致位于第 90 行,您也可以通过搜索 this.socket.addEventListener 找到它)。
该监听器会为每种已知的消息类型创建一个 CustomEvent 对象,并将其派发给所有已注册的相应监听器。
扩展程序可以遵循标准的 Javascript 模式来注册事件接收(此操作通常在 setup() 函数中完成):
message_type 并非内置消息类型,系统会自动将其添加至已知消息类型列表。
注册的 messageHandler 函数在被调用时,会接收到一个 CustomEvent 对象。
该对象是对 socket 事件的扩展,额外增加了一个 .detail 属性,此属性是一个包含了服务器所发送数据的字典。因此,通常的使用方式如下:
内置消息类型
在工作流执行期间(或当执行队列状态发生变化时),PromptExecutor 会通过 PromptServer 实例的 send_sync 方法向客户端发送以下类型的消息。
扩展程序可以注册监听这些消息中的任意一种。
| 事件类型 (event) | 触发时机 | 数据内容 (data) | 
|---|---|---|
| execution_start | 当一个提示 (prompt) 即将开始执行时 | prompt_id(提示ID) | 
| execution_error | 当执行过程中发生错误时 | prompt_id(提示ID),以及其他附加错误信息 | 
| execution_interrupted | 当某个节点抛出 InterruptProcessingException异常导致执行中断时 | prompt_id(提示ID)、node_id(节点ID)、node_type(节点类型) 以及executed(一个包含已执行节点ID的列表) | 
| execution_cached | 在执行开始阶段 | prompt_id(提示ID)、nodes(一个节点ID列表,这些节点的缓存输出将被复用,因此这些节点会被跳过执行) | 
| execution_success | 当提示中的所有节点都已成功执行时 | prompt_id,timestamp(时间戳) | 
| executing | 当一个新节点即将开始执行时 | node(当前执行的节点ID,若为None则表示整个提示执行完毕)、prompt_id(提示ID) | 
| executed | 当一个节点执行完毕并返回了用户界面 (UI) 元素时 | node(节点ID)、prompt_id(提示ID)、output(节点返回的UI数据) | 
| progress | 在执行某个实现了特定进度报告钩子 (hook) 的节点期间 | node(节点ID)、prompt_id(提示ID)、value(当前进度值)、max(最大进度值) | 
| status | 当执行队列的状态发生变化时 | exec_info(一个字典,其中包含queue_remaining,表示队列中剩余的任务数量) | 
关于 executed 消息的使用
值得注意的是,executed 消息并非在每个节点完成执行时都会发送(这一点与 executing 消息不同),
它仅在节点执行后需要更新用户界面时才会触发。
要实现这一点,节点的Python主执行函数需要返回一个字典,而非通常的元组:
a_new_dictionary 的内容便会作为 executed 消息中 output 字段的值发送给客户端。
如果节点本身没有输出(即不产生传递给下游节点的数据),那么返回字典中的 result 键可以省略(例如,可以参考 nodes.py 文件中 SaveImage 节点的实现方式)。
自定义消息类型
如前所述,在客户端,只需为自定义的消息类型名称注册一个监听器,即可轻松添加对新消息类型的处理。获取当前节点 ID (node_id)
大多数内置消息的node 字段都包含了当前正在执行的节点 ID。在自定义消息中,您很可能也需要包含此信息。
在服务器端,可以通过一个隐藏输入来获取节点 ID。这需要在节点的 INPUT_TYPES 字典中添加一个 hidden 键来实现: