diff --git a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation.rs b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation.rs index d1217aefa..fb65a02c5 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/ui_editor/commands/separation.rs @@ -16,7 +16,6 @@ use platform_llm::{ }; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use sha2::{Digest, Sha256}; use std::fs; use std::path::{Path, PathBuf}; use ts_rs::TS; @@ -331,18 +330,10 @@ pub fn separation_sidecar_dir(root: &Path, asset_id: &str) -> Result>(); + for node in batch { + state.problematic_nodes.push(ProblematicNode { + node_id: node.id.clone(), + problem_description: error.clone(), + rework_count: MAX_REWORK_COUNT, + }); + } + if let Some(tree) = state.unprocessed_trees.get_mut(tree_index) { + remove_ids(&mut tree.root, &ids); + } +} + fn increment_rework_count(node: &mut SeparationNode, id: &NodeId, count: u32) { if node.id == *id { node.rework_count = count; @@ -662,22 +675,41 @@ pub(crate) async fn separate_ui_impl( let Some(current_tree) = separation.unprocessed_trees.get(tree_index) else { break; }; - let batch = next_leaf_batch(current_tree); - if batch.is_empty() { + let batch_nodes = next_leaf_batch(current_tree) + .into_iter() + .cloned() + .collect::>(); + if batch_nodes.is_empty() { break; } + let batch = batch_nodes.iter().collect::>(); let prompt = gen_extract_prompt(&batch.iter().map(|n| n.note.clone()).collect::>()); let marker_path = sidecar.join(format!("marked-{}.png", separation.bound.len())); - let marked_url = build_marked_image(&source_url, &batch, &marker_path)?; - let processed_url = raw_image_edit( + let marked_url = match build_marked_image(&source_url, &batch, &marker_path) { + Ok(value) => value, + Err(error) => { + mark_batch_problematic(&mut separation, tree_index, &batch, error); + write_separation_state(&state_path, &separation)?; + continue; + } + }; + let processed_url = match raw_image_edit( &session, &marked_url, &prompt, image.pixel_size.x as u32, image.pixel_size.y as u32, ) - .await?; + .await + { + Ok(value) => value, + Err(error) => { + mark_batch_problematic(&mut separation, tree_index, &batch, error); + write_separation_state(&state_path, &separation)?; + continue; + } + }; let processed_path = sidecar.join(format!("processed-{}.png", separation.bound.len())); let processed_bytes = base64::engine::general_purpose::STANDARD .decode( @@ -688,7 +720,14 @@ pub(crate) async fn separate_ui_impl( ) .map_err(|e| e.to_string())?; fs::write(&processed_path, processed_bytes).map_err(|e| e.to_string())?; - let binding = visual_binding(source_url.clone(), processed_url, &batch).await?; + let binding = match visual_binding(source_url.clone(), processed_url, &batch).await { + Ok(value) => value, + Err(error) => { + mark_batch_problematic(&mut separation, tree_index, &batch, error); + write_separation_state(&state_path, &separation)?; + continue; + } + }; let mut cut_paths = std::collections::HashMap::new(); for decision in &binding.decisions { if let BindingDecision::Ok {