comfyui_client/meta.rs
1use crate::ClientError;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use std::{collections::HashMap, fmt::Debug};
5use tokio_tungstenite::tungstenite;
6
7/// Contains information about a prompt, including its execution details.
8#[derive(Serialize, Deserialize, Debug)]
9pub struct PromptInfo {
10 /// Execution information related to the prompt.
11 pub exec_info: ExecInfo,
12}
13
14/// Contains execution details such as the remaining queue length.
15#[derive(Serialize, Deserialize, Debug)]
16pub struct ExecInfo {
17 /// The number of remaining tasks in the execution queue.
18 pub queue_remaining: usize,
19}
20
21/// Represents file information including filename, subfolder, and file type.
22#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
23pub struct FileInfo {
24 /// The name of the file.
25 #[serde(alias = "name")]
26 pub filename: String,
27 /// The subfolder where the file is located.
28 pub subfolder: String,
29 /// The type of the file.
30 pub r#type: String,
31}
32
33/// Represents a prompt with an identifier, a number, and potential node errors.
34#[derive(Serialize, Deserialize, Debug)]
35pub struct PromptStatus {
36 /// Unique identifier for the prompt.
37 pub prompt_id: String,
38 /// A numeric identifier for the prompt.
39 pub number: usize,
40 /// A mapping of node identifiers to error details in JSON format.
41 pub node_errors: HashMap<String, Value>,
42}
43
44/// Represents the history of outputs for a prompt.
45#[derive(Serialize, Deserialize, Debug)]
46pub struct History {
47 /// A mapping of output identifiers to their corresponding images.
48 pub outputs: HashMap<String, Images>,
49}
50
51/// Contains an optional list of image file information.
52#[derive(Serialize, Deserialize, Debug)]
53pub struct Images {
54 /// A vector of file information objects, if available.
55 pub images: Option<Vec<FileInfo>>,
56}
57
58/// Represents events emitted by the ComfyUI client during workflow execution.
59///
60/// This structure allows for clear separation between service-level events and
61/// client-side connection management events.
62#[non_exhaustive]
63pub enum Event {
64 /// `Comfy` events originate from the ComfyUI service itself
65 Comfy(ComfyEvent),
66 /// `Connection` events relate to WebSocket connection management
67 Connection(ConnectionEvent),
68}
69
70/// Represents events emitted by the ComfyUI service during workflow execution.
71///
72/// This enum encapsulates various event types that occur during the lifecycle
73/// of a workflow, from queuing to completion. Each variant contains specific
74/// data relevant to that event type. The `Unknown` variant captures any
75/// unrecognized events from the API.
76#[derive(Serialize, Deserialize, Debug)]
77#[serde(tag = "type")]
78#[serde(rename_all = "snake_case")]
79pub enum ComfyEvent {
80 /// A status event containing queue and execution information.
81 Status {
82 /// Data payload for the status event, including execution information.
83 data: StatusEventData,
84 /// Optional session identifier associated with this event.
85 sid: Option<String>,
86 },
87 /// A progress event indicating current progress of an operation.
88 Progress {
89 /// Data payload containing current and maximum progress values.
90 data: ProgressEventData,
91 },
92 /// An event indicating that a node has completed execution along with its
93 /// output data.
94 Executed {
95 /// Data payload containing node output information and associated
96 /// images.
97 data: ExecutedEventData,
98 },
99 /// An event indicating that a node is currently executing.
100 Executing {
101 /// Data payload identifying the currently executing node.
102 data: ExecutingEventData,
103 },
104 /// An event signaling the start of execution for a prompt.
105 ExecutionStart {
106 /// Data payload containing prompt ID and timestamp information.
107 data: ExecutionStartEventData,
108 },
109 /// An event signaling that an error occurred during execution.
110 ExecutionError {
111 /// Data payload containing detailed error information and context.
112 data: ExecutionErrorEventData,
113 },
114 /// An event indicating that the execution results were retrieved from the
115 /// cache.
116 ExecutionCached {
117 /// Data payload containing information about which nodes were retrieved
118 /// from cache.
119 data: ExecutionCachedEventData,
120 },
121 /// An event indicating that the execution was interrupted.
122 ExecutionInterrupted {
123 /// Data payload containing details about where and why the execution
124 /// was interrupted.
125 data: ExecutionInterruptedEventData,
126 },
127 /// An event indicating that the entire workflow has executed successfully.
128 ExecutionSuccess {
129 /// Data payload containing the prompt ID of the successfully executed
130 /// workflow.
131 data: ExecutionSuccessEventData,
132 },
133 /// An unknown event type that encapsulates raw JSON data for events not
134 /// explicitly defined.
135 #[serde(skip)]
136 Unknown(Value),
137}
138
139/// Represents events that are not part of the standard ComfyUI API
140/// but are added by the client for additional functionality.
141///
142/// These events are used internally by the client to handle WebSocket
143/// connection management and error reporting, allowing the application to
144/// respond to connection-related events that aren't part of the ComfyUI
145/// protocol.
146#[derive(Debug)]
147#[non_exhaustive]
148pub enum ConnectionEvent {
149 /// Event indicating a successful reconnection to the WebSocket.
150 ///
151 /// Emitted when the client successfully reestablishes a connection after
152 /// a disconnection.
153 WSReconnectSuccess,
154
155 /// Event containing an error that occurred during a reconnection attempt.
156 ///
157 /// Provides detailed error information about why a reconnection attempt
158 /// failed, allowing clients to implement appropriate retry or fallback
159 /// strategies.
160 WSReconnectError(ClientError),
161
162 /// Event containing an error that occurred while receiving messages.
163 ///
164 /// Indicates that an error occurred in the WebSocket communication channel
165 /// while trying to receive messages from the ComfyUI server.
166 WSReceiveError(tungstenite::Error),
167}
168
169/// Event payload for a status event, containing execution information.
170///
171/// This structure is received when ComfyUI sends a status update, typically
172/// containing information about the current execution queue state.
173#[derive(Serialize, Deserialize, Debug)]
174pub struct StatusEventData {
175 /// Execution information associated with the event, including queue
176 /// details.
177 pub status: StatusEventStatus,
178}
179
180/// Container for execution information within a status event.
181///
182/// Holds detailed execution information about the current state of the ComfyUI
183/// service, such as the number of remaining items in the execution queue.
184#[derive(Serialize, Deserialize, Debug)]
185pub struct StatusEventStatus {
186 /// Execution information including queue status and other execution
187 /// metrics.
188 pub exec_info: ExecInfo,
189}
190
191/// Event payload for a progress update, including current value and maximum
192/// value.
193///
194/// This structure is received when ComfyUI reports progress of an operation,
195/// such as image generation or processing.
196#[derive(Serialize, Deserialize, Debug)]
197pub struct ProgressEventData {
198 /// The current progress value representing the completed steps.
199 pub value: usize,
200 /// The maximum progress value representing the total number of steps.
201 pub max: usize,
202}
203
204/// Represents the output of an executed node.
205///
206/// Contains the results produced by a node in the workflow after successful
207/// execution. This can include generated or processed images in the `images`
208/// field, as well as other arbitrary output data in the `others` map.
209#[derive(Serialize, Deserialize, Debug)]
210pub struct ExecutedOutput {
211 /// Optional list of image file information objects generated or processed
212 /// by the node.
213 pub images: Option<Vec<FileInfo>>,
214 /// Additional output data that doesn't fit into predefined categories.
215 #[serde(flatten)]
216 pub others: HashMap<String, Value>,
217}
218
219/// Event payload for a completed execution, including the node identifier,
220/// prompt ID, and output data.
221///
222/// This structure is received when a specific node in the workflow completes
223/// execution and produces output, such as generated images.
224#[derive(Serialize, Deserialize, Debug)]
225pub struct ExecutedEventData {
226 /// Identifier of the node that completed execution.
227 pub node: String,
228 /// The prompt ID associated with the execution.
229 pub prompt_id: String,
230 /// The output generated by the executed node, containing resulting images
231 /// or other data.
232 pub output: Option<ExecutedOutput>,
233}
234
235/// Event payload for an execution in progress, including the node identifier
236/// and prompt ID.
237///
238/// This structure is received when ComfyUI begins executing a specific node in
239/// the workflow. It provides information about which node is currently being
240/// processed.
241#[derive(Serialize, Deserialize, Debug)]
242pub struct ExecutingEventData {
243 /// Identifier of the node currently executing. May be None in certain
244 /// cases.
245 pub node: Option<String>,
246 /// Optional display name of the executing node, providing a more
247 /// user-friendly identifier.
248 pub display_node: Option<String>,
249 /// The prompt ID associated with the execution, linking this event to a
250 /// specific workflow run.
251 pub prompt_id: String,
252}
253
254/// Event payload indicating that the execution has started.
255///
256/// This structure is received when ComfyUI begins executing a workflow.
257/// It serves as an initial notification that the workflow processing has begun
258/// and provides timing information for performance tracking.
259#[derive(Serialize, Deserialize, Debug)]
260pub struct ExecutionStartEventData {
261 /// The prompt ID for which the execution has started, identifying the
262 /// workflow run.
263 pub prompt_id: String,
264 /// Unix timestamp indicating when the execution started, useful for timing
265 /// analysis.
266 pub timestamp: u64,
267}
268
269/// Event payload for an execution error, containing details about the error and
270/// its context.
271///
272/// This structure is received when an error occurs during workflow execution.
273/// It provides comprehensive information about the error, including where it
274/// occurred and the state of inputs and outputs at the time of the error.
275#[derive(Serialize, Deserialize, Debug)]
276pub struct ExecutionErrorEventData {
277 /// The prompt ID associated with the error, identifying the workflow
278 /// execution.
279 pub prompt_id: String,
280 /// The identifier of the node where the error occurred within the workflow.
281 pub node_id: String,
282 /// The type of the node where the error occurred (e.g., "CLIPTextEncode",
283 /// "KSampler").
284 pub node_type: String,
285 /// A list of node identifiers that were successfully executed before the
286 /// error occurred.
287 pub executed: Vec<String>,
288 /// The error message from the exception, describing what went wrong.
289 pub exception_message: String,
290 /// The type of the exception that was raised (e.g., "ValueError",
291 /// "RuntimeError").
292 pub exception_type: String,
293 /// A traceback of the error as a list of strings, showing the execution
294 /// path that led to the error.
295 pub traceback: Vec<String>,
296 /// The current input values at the time of the error, mapping input names
297 /// to their values.
298 pub current_inputs: HashMap<String, Value>,
299 /// The current output values at the time of the error, mapping output names
300 /// to their values.
301 pub current_outputs: HashMap<String, Value>,
302}
303
304/// Event payload indicating that the execution result was obtained from the
305/// cache rather than recalculated.
306///
307/// This structure is received when ComfyUI uses cached results for nodes in the
308/// workflow, which can significantly speed up execution when identical
309/// operations are performed.
310#[derive(Serialize, Deserialize, Debug)]
311pub struct ExecutionCachedEventData {
312 /// A list of node identifiers that were retrieved from the cache instead of
313 /// being re-executed.
314 pub nodes: Vec<String>,
315 /// The prompt ID associated with the cached execution, linking this event
316 /// to a specific workflow run.
317 pub prompt_id: String,
318 /// Unix timestamp indicating when the cached execution result was
319 /// retrieved, useful for timing analysis.
320 pub timestamp: u64,
321}
322
323/// Event payload for an interrupted execution, containing details about the
324/// interruption.
325///
326/// This structure is received when the workflow execution is manually
327/// interrupted or terminated before completion, providing context about what
328/// was executing at the time of interruption.
329#[derive(Serialize, Deserialize, Debug)]
330pub struct ExecutionInterruptedEventData {
331 /// The prompt ID associated with the interruption, identifying the workflow
332 /// execution that was stopped.
333 pub prompt_id: String,
334 /// The identifier of the node where the execution was interrupted,
335 /// indicating which operation was in progress.
336 pub node_id: String,
337 /// The type of the node that was interrupted (e.g., "KSampler",
338 /// "VAEDecode"), helping identify what operation was stopped.
339 pub node_type: String,
340 /// A list of node identifiers that were successfully executed before the
341 /// interruption occurred.
342 pub executed: Vec<String>,
343}
344
345/// Event payload indicating successful completion of workflow execution.
346///
347/// This structure is received when an entire workflow has completed execution
348/// successfully. It serves as a final notification that all nodes in the
349/// workflow have been processed without errors, and the workflow is complete.
350#[derive(Serialize, Deserialize, Debug)]
351pub struct ExecutionSuccessEventData {
352 /// The prompt ID associated with the successful execution, identifying the
353 /// completed workflow.
354 pub prompt_id: String,
355}
356
357/// `Prompt` param for
358/// [`ComfyUIClient::post_prompt`](crate::ComfyUIClient::post_prompt).
359///
360/// Represents a prompt that can be submitted to the ComfyUI server for
361/// execution. The prompt defines the workflow to be executed, including all
362/// nodes and their connections, as well as the input parameters for each node.
363pub enum Prompt<'a> {
364 /// A string slice representing the prompt in JSON format.
365 ///
366 /// Use this variant when you have a JSON string representation of the
367 /// workflow.
368 Str(&'a str),
369
370 /// A JSON value representing the prompt data.
371 ///
372 /// Use this variant when you have already parsed the workflow into a
373 /// serde_json Value.
374 Value(&'a Value),
375}
376
377impl<'a> From<&'a str> for Prompt<'a> {
378 fn from(value: &'a str) -> Self {
379 Prompt::Str(value)
380 }
381}
382
383impl<'a> From<&'a String> for Prompt<'a> {
384 fn from(value: &'a String) -> Self {
385 Prompt::Str(value)
386 }
387}
388
389impl<'a> From<&'a Value> for Prompt<'a> {
390 fn from(value: &'a Value) -> Self {
391 Prompt::Value(value)
392 }
393}
394
395#[cfg(test)]
396mod tests {
397 use super::*;
398 use serde_json::json;
399
400 /// Tests serialization of different event types.
401 #[test]
402 fn test_serialize_event() {
403 let ev = ComfyEvent::Status {
404 data: StatusEventData {
405 status: StatusEventStatus {
406 exec_info: ExecInfo { queue_remaining: 0 },
407 },
408 },
409 sid: None,
410 };
411 let value = serde_json::to_value(&ev).unwrap();
412 assert_eq!(
413 value,
414 json!({
415 "type": "status",
416 "data": {
417 "status": {
418 "exec_info": {
419 "queue_remaining": 0,
420 }
421 }
422 },
423 "sid": null
424 })
425 );
426
427 let ev = ComfyEvent::ExecutionStart {
428 data: ExecutionStartEventData {
429 prompt_id: "xxxxxx".to_string(),
430 timestamp: 123456789,
431 },
432 };
433 let value = serde_json::to_value(&ev).unwrap();
434 assert_eq!(
435 value,
436 json!({
437 "type": "execution_start",
438 "data": {
439 "prompt_id": "xxxxxx",
440 "timestamp": 123456789
441 }
442 })
443 );
444 }
445}