Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/comfyui-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "comfyui-api"
version = "0.2.1"
edition = "2021"
edition = "2024"
description = "Stable Diffusion ComfyUI API wrapper"
readme = "README.md"
license = "MIT"
Expand Down
5 changes: 5 additions & 0 deletions crates/comfyui-api/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ impl Api {
})
}

/// Returns the client id.
pub fn client_id(&self) -> uuid::Uuid {
self.client_id
}

/// Returns a new `Api` instance with the given `reqwest::Client` and URL as a string value.
///
/// # Arguments
Expand Down
10 changes: 5 additions & 5 deletions crates/comfyui-api/src/api/websocket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ pub enum WebSocketApiError {
ParseError(#[from] url::ParseError),
/// Error parsing endpoint URL
#[error("Failed to parse endpoint URL")]
ConnectFailed(#[from] tokio_tungstenite::tungstenite::Error),
ConnectFailed(#[from] Box<tokio_tungstenite::tungstenite::Error>),
/// An error occurred while parsing the response from the API.
#[error("Parsing response failed")]
InvalidResponse(#[from] serde_json::Error),
/// An error occurred while reading websocket message.
#[error("Error occurred while reading websocket message")]
ReadFailed(#[source] tokio_tungstenite::tungstenite::Error),
ReadFailed(#[source] Box<tokio_tungstenite::tungstenite::Error>),
}

type Result<T> = std::result::Result<T, WebSocketApiError>;
Expand Down Expand Up @@ -65,7 +65,7 @@ impl WebsocketApi {
&self,
endpoint: &Url,
) -> Result<impl FusedStream<Item = Result<PreviewOrUpdate>>> {
let (connection, _) = connect_async(endpoint).await?;
let (connection, _) = connect_async(endpoint).await.map_err(Box::new)?;
Ok(connection.filter_map(|m| async {
match m {
Ok(m) => match m {
Expand All @@ -82,7 +82,7 @@ impl WebsocketApi {
None
}
},
Err(e) => Some(Err(WebSocketApiError::ReadFailed(e))),
Err(e) => Some(Err(WebSocketApiError::ReadFailed(Box::new(e)))),
}
}))
}
Expand All @@ -106,7 +106,7 @@ impl WebsocketApi {
/// # Returns
///
/// A `Stream` of `Update` values. These contain progress updates for a task.
pub async fn updates(&self) -> Result<impl FusedStream<Item = Result<Update>>> {
pub async fn updates(&self) -> Result<impl FusedStream<Item = Result<Update>> + use<'_>> {
Ok(self.connect_impl().await?.filter_map(|m| async {
match m {
Ok(PreviewOrUpdate::Update(u)) => Some(Ok(u)),
Expand Down
52 changes: 33 additions & 19 deletions crates/comfyui-api/src/comfy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@
CreateApiFailed(#[from] api::ApiError),
/// Execution was interrupted
#[error("Execution was interrupted: node {} ({})", response.node_id, response.node_type)]
ExecutionInterrupted { response: ExecutionInterrupted },
ExecutionInterrupted {
response: Box<ExecutionInterrupted>,
},
/// Error occurred during execution
#[error("Error occurred during execution: {exception_type}: {exception_message}")]
ExecutionError {
Expand Down Expand Up @@ -82,15 +84,20 @@
history: HistoryApi,
upload: UploadApi,
view: ViewApi,
websocket: WebsocketApi,
}

impl Default for Comfy {
fn default() -> Self {
let client_id = Uuid::new_v4();
let api = Api::default();
Self {
history: api.history().expect("failed to create history api"),
upload: api.upload().expect("failed to create upload api"),
view: api.view().expect("failed to create view api"),
websocket: api
.websocket_with_client(client_id)
.expect("failed to create websocket api"),
api,
}
}
Expand All @@ -99,11 +106,13 @@
impl Comfy {
/// Returns a new `Comfy` instance with default settings.
pub fn new() -> Result<Self> {
let client_id = Uuid::new_v4();
let api = Api::default();
Ok(Self {
history: api.history()?,
upload: api.upload()?,
view: api.view()?,
websocket: api.websocket_with_client(client_id)?,
api,
})
}
Expand All @@ -121,11 +130,13 @@
where
S: AsRef<str>,
{
let client_id = Uuid::new_v4();
let api = Api::new_with_url(url.as_ref())?;
Ok(Self {
history: api.history()?,
upload: api.upload()?,
view: api.view()?,
websocket: api.websocket_with_client(client_id)?,
api,
})
}
Expand All @@ -144,11 +155,13 @@
where
S: AsRef<str>,
{
let client_id = Uuid::new_v4();
let api = Api::new_with_client_and_url(client, url.as_ref())?;
Ok(Self {
history: api.history()?,
upload: api.upload()?,
view: api.view()?,
websocket: api.websocket_with_client(client_id)?,
api,
})
}
Expand All @@ -156,31 +169,31 @@
async fn filter_update(&self, update: Update, target_prompt_id: Uuid) -> Result<Option<State>> {
match update {
Update::Executing(data) => {
if data.node.is_none() {
if let Some(prompt_id) = data.prompt_id {
if prompt_id != target_prompt_id {
return Ok(None);
}
let task = self
.history
.get_prompt(&prompt_id)
.await
.map_err(ComfyApiError::PromptTaskNotFound)?;
let images = task
.outputs
.nodes
.into_iter()
.filter_map(|(key, value)| {
if let NodeOutputOrUnknown::NodeOutput(output) = value {
Some((key, output.images))
} else {
None
}
})
.collect::<Vec<(String, Vec<Image>)>>();
return Ok(Some(State::Finished(images)));
}
}

Check warning on line 196 in crates/comfyui-api/src/comfy/mod.rs

View workflow job for this annotation

GitHub Actions / check-rust (macos-14)

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> crates/comfyui-api/src/comfy/mod.rs:172:17 | 172 | / if data.node.is_none() { 173 | | if let Some(prompt_id) = data.prompt_id { 174 | | if prompt_id != target_prompt_id { 175 | | return Ok(None); ... | 196 | | } | |_________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if help: collapse nested if block | 172 ~ if data.node.is_none() 173 ~ && let Some(prompt_id) = data.prompt_id { 174 | if prompt_id != target_prompt_id { ... 194 | return Ok(Some(State::Finished(images))); 195 ~ } |

Check warning on line 196 in crates/comfyui-api/src/comfy/mod.rs

View workflow job for this annotation

GitHub Actions / check-rust (ubuntu-latest)

this `if` statement can be collapsed

warning: this `if` statement can be collapsed --> crates/comfyui-api/src/comfy/mod.rs:172:17 | 172 | / if data.node.is_none() { 173 | | if let Some(prompt_id) = data.prompt_id { 174 | | if prompt_id != target_prompt_id { 175 | | return Ok(None); ... | 196 | | } | |_________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if help: collapse nested if block | 172 ~ if data.node.is_none() 173 ~ && let Some(prompt_id) = data.prompt_id { 174 | if prompt_id != target_prompt_id { ... 194 | return Ok(Some(State::Finished(images))); 195 ~ } |
Ok(None)
}
Update::Executed(data) => {
Expand All @@ -193,7 +206,9 @@
if data.prompt_id != target_prompt_id {
return Ok(None);
}
Err(ComfyApiError::ExecutionInterrupted { response: data })
Err(ComfyApiError::ExecutionInterrupted {
response: Box::new(data),
})
}
Update::ExecutionError(data) => {
if data.execution_status.prompt_id != target_prompt_id {
Expand All @@ -212,25 +227,24 @@
&'a self,
prompt: &Prompt,
) -> Result<impl Stream<Item = Result<State>> + 'a> {
let client_id = Uuid::new_v4();
let prompt_api = self.api.prompt_with_client(client_id)?;
let websocket_api = self.api.websocket_with_client(client_id)?;
let stream = websocket_api
.updates()
.await
.map_err(ComfyApiError::ReceiveUpdateFailure)?;
let prompt_api = self.api.prompt_with_client(self.api.client_id())?;
let response = prompt_api.send(prompt).await?;
let prompt_id = response.prompt_id;
Ok(stream.filter_map(move |msg| async move {
match msg {
Ok(msg) => match self.filter_update(msg, prompt_id).await {
Ok(Some(images)) => Some(Ok(images)),
Ok(None) => None,
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(ComfyApiError::ReceiveUpdateFailure(e))),
}
}))
Ok(self
.websocket
.updates()
.await
.map_err(ComfyApiError::ReceiveUpdateFailure)?
.filter_map(move |msg| async move {
match msg {
Ok(msg) => match self.filter_update(msg, prompt_id).await {
Ok(Some(images)) => Some(Ok(images)),
Ok(None) => None,
Err(e) => Some(Err(e)),
},
Err(e) => Some(Err(ComfyApiError::ReceiveUpdateFailure(e))),
}
}))
}

/// Executes a prompt and returns a stream of generated images.
Expand Down
2 changes: 1 addition & 1 deletion crates/sal-e-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "sal-e-api"
version = "0.2.1"
edition = "2021"
edition = "2024"
description = "Stable-Diffusion Abstraction Layer"
readme = "README.md"
license = "MIT"
Expand Down
6 changes: 3 additions & 3 deletions crates/sal-e-api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub struct Response {
pub enum ComfyPromptApiError {
/// Error creating a ComfyUI Client
#[error("Error creating a ComfyUI Client")]
CreateClient(#[from] comfyui_api::comfy::ComfyApiError),
CreateClient(#[from] Box<comfyui_api::comfy::ComfyApiError>),
}

/// Struct wrapping a connection to the ComfyUI API.
Expand Down Expand Up @@ -50,7 +50,7 @@ impl ComfyPromptApi {
/// A new `ComfyPromptApi` instance on success, or an error if there was a failure in the ComfyUI API client.
pub fn new(prompt: comfyui_api::models::Prompt) -> Result<Self, ComfyPromptApiError> {
Ok(Self {
client: comfyui_api::comfy::Comfy::new()?,
client: comfyui_api::comfy::Comfy::new().map_err(Box::new)?,
params: crate::gen_params::ComfyParams {
prompt: Some(prompt),
count: 1,
Expand Down Expand Up @@ -79,7 +79,7 @@ impl ComfyPromptApi {
S: AsRef<str>,
{
Ok(Self {
client: comfyui_api::comfy::Comfy::new_with_url(url)?,
client: comfyui_api::comfy::Comfy::new_with_url(url).map_err(Box::new)?,
params: crate::gen_params::ComfyParams {
prompt: Some(prompt),
count: 1,
Expand Down
2 changes: 1 addition & 1 deletion crates/stable-diffusion-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "stable-diffusion-api"
version = "0.1.2"
edition = "2021"
edition = "2024"
description = "Stable Diffusion WebUI API wrapper"
readme = "README.md"
license = "MIT"
Expand Down
4 changes: 2 additions & 2 deletions crates/stable-diffusion-api/src/img2img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
/// # Arguments
///
/// * `seed` - An i64 value representing the seed for random number generation.
/// Set to `-1` to randomize.
/// Set to `-1` to randomize.

Check warning on line 243 in crates/stable-diffusion-api/src/img2img.rs

View workflow job for this annotation

GitHub Actions / check-rust (ubuntu-latest)

doc list item overindented

warning: doc list item overindented --> crates/stable-diffusion-api/src/img2img.rs:243:9 | 243 | /// Set to `-1` to randomize. | ^^^^^^^^^ help: try using ` ` (2 spaces) | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
///
/// # Example
///
Expand All @@ -258,7 +258,7 @@
/// # Arguments
///
/// * `subseed` - An i64 value representing the subseed for random number generation.
/// Set to `-1` to randomize.
/// Set to `-1` to randomize.

Check warning on line 261 in crates/stable-diffusion-api/src/img2img.rs

View workflow job for this annotation

GitHub Actions / check-rust (ubuntu-latest)

doc list item overindented

warning: doc list item overindented --> crates/stable-diffusion-api/src/img2img.rs:261:9 | 261 | /// Set to `-1` to randomize. | ^^^^^^^^^^^^ help: try using ` ` (2 spaces) | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
///
/// # Example
///
Expand Down
4 changes: 2 additions & 2 deletions crates/stable-diffusion-api/src/txt2img.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@
/// # Arguments
///
/// * `seed` - An i64 value representing the seed for random number generation.
/// Set to `-1` to randomize.
/// Set to `-1` to randomize.

Check warning on line 159 in crates/stable-diffusion-api/src/txt2img.rs

View workflow job for this annotation

GitHub Actions / check-rust (ubuntu-latest)

doc list item overindented

warning: doc list item overindented --> crates/stable-diffusion-api/src/txt2img.rs:159:9 | 159 | /// Set to `-1` to randomize. | ^^^^^^^^^ help: try using ` ` (2 spaces) | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items = note: `#[warn(clippy::doc_overindented_list_items)]` on by default
///
/// # Example
///
Expand All @@ -174,7 +174,7 @@
/// # Arguments
///
/// * `subseed` - An i64 value representing the subseed for random number generation.
/// Set to `-1` to randomize.
/// Set to `-1` to randomize.

Check warning on line 177 in crates/stable-diffusion-api/src/txt2img.rs

View workflow job for this annotation

GitHub Actions / check-rust (ubuntu-latest)

doc list item overindented

warning: doc list item overindented --> crates/stable-diffusion-api/src/txt2img.rs:177:9 | 177 | /// Set to `-1` to randomize. | ^^^^^^^^^^^^ help: try using ` ` (2 spaces) | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
///
/// # Example
///
Expand Down
2 changes: 1 addition & 1 deletion crates/stable-diffusion-bot/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "stable-diffusion-bot"
version = "0.2.1"
edition = "2021"
edition = "2024"
description = "Stable Diffusion Telegram Bot"
readme = "README.md"
license = "MIT"
Expand Down
10 changes: 4 additions & 6 deletions crates/stable-diffusion-bot/src/bot/handlers/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,13 +388,12 @@ pub(crate) async fn handle_txt2img_settings_value(
text: String,
(selection, mut txt2img, img2img): (Option<String>, Box<dyn GenParams>, Box<dyn GenParams>),
) -> anyhow::Result<()> {
if let Some(ref setting) = selection {
if let Err(e) = update_txt2img_setting(txt2img.as_mut(), setting, text) {
if let Some(ref setting) = selection
&& let Err(e) = update_txt2img_setting(txt2img.as_mut(), setting, text) {
bot.send_message(msg.chat.id, format!("Please enter a valid value: {e:?}."))
.await?;
return Ok(());
}
}

let bot_state = BotState::SettingsTxt2Img { selection: None };

Expand All @@ -419,13 +418,12 @@ pub(crate) async fn handle_img2img_settings_value(
text: String,
(selection, txt2img, mut img2img): (Option<String>, Box<dyn GenParams>, Box<dyn GenParams>),
) -> anyhow::Result<()> {
if let Some(ref setting) = selection {
if let Err(e) = update_img2img_setting(img2img.as_mut(), setting, text) {
if let Some(ref setting) = selection
&& let Err(e) = update_img2img_setting(img2img.as_mut(), setting, text) {
bot.send_message(msg.chat.id, format!("Please enter a valid value: {e:?}."))
.await?;
return Ok(());
}
}

let bot_state = BotState::SettingsImg2Img { selection: None };

Expand Down
Loading