feat(api): add model loading, unloading, and uploading endpoints

This commit introduces new API endpoints for managing AI models:
- /models/{model_name}/load: Load a specific model into memory with validation
- /models/{model_name}/unload: Unload a specific model from memory
- /models/upload: Handle model file uploads via multipart form data

The implementation includes proper error handling, model existence validation, and integrates with the existing model manager system. The endpoints return structured JSON responses indicating success or failure states.

The changes also update dependencies to include actix-multipart and futures-util for handling multipart requests, and add path handling utilities for file operations.
This commit is contained in:
2026-03-03 17:34:37 +01:00
parent 027495829d
commit e5db9bc425
14 changed files with 1181 additions and 4 deletions

116
src/frontend.rs Normal file
View File

@@ -0,0 +1,116 @@
//! Frontend for ComfyUI-Rust using egui
use eframe::egui;
// Simple UI that connects to our local backend
pub struct ComfyUiFrontend {
prompt: String,
negative_prompt: String,
width: u32,
height: u32,
steps: u32,
cfg_scale: f32,
is_generating: bool,
model_name: String,
}
impl ComfyUiFrontend {
pub fn new(_cc: &eframe::CreationContext) -> Self {
Self {
prompt: "A beautiful sunset over the ocean".to_string(),
negative_prompt: "".to_string(),
width: 512,
height: 512,
steps: 30,
cfg_scale: 7.0,
is_generating: false,
model_name: "stable-diffusion-v1-4".to_string(),
}
}
fn generate_image(&mut self) {
if self.is_generating {
return;
}
self.is_generating = true;
let prompt = self.prompt.clone();
// Simulate async operation by spawning background task that updates UI after delay
std::thread::spawn(move || {
// Simulate network delay and processing time (5 seconds)
std::thread::sleep(std::time::Duration::from_secs(3));
println!("Image generation completed for: {}", prompt);
});
}
}
impl eframe::App for ComfyUiFrontend {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("ComfyUI-Rust Frontend");
// Model selection
ui.horizontal(|ui| {
ui.label("Model:");
ui.text_edit_singleline(&mut self.model_name);
});
// Prompt input
ui.separator();
ui.label("Prompt:");
ui.text_edit_multiline(&mut self.prompt);
ui.label("Negative Prompt:");
ui.text_edit_multiline(&mut self.negative_prompt);
// Generation parameters
ui.separator();
ui.horizontal(|ui| {
ui.label("Width:");
ui.add(egui::Slider::new(&mut self.width, 256..=1024).step_by(64.0));
ui.label("Height:");
ui.add(egui::Slider::new(&mut self.height, 256..=1024).step_by(64.0));
});
ui.horizontal(|ui| {
ui.label("Steps:");
ui.add(egui::Slider::new(&mut self.steps, 10..=100).step_by(1.0));
ui.label("CFG Scale:");
ui.add(egui::Slider::new(&mut self.cfg_scale, 1.0..=20.0).step_by(0.5));
});
// Generate button
if ui.button("Generate Image").clicked() {
self.generate_image();
}
// Status and image preview
ui.separator();
if self.is_generating {
ui.label("Generating image...");
} else {
ui.label("Ready to generate");
}
});
}
}
fn main() -> eframe::Result<()> {
let options = eframe::NativeOptions {
viewport: egui::ViewportBuilder::default()
.with_title("ComfyUI-Rust Frontend")
.with_inner_size([800.0, 600.0])
.with_min_inner_size([400.0, 300.0]),
..Default::default()
};
eframe::run_native(
"ComfyUI-Rust",
options,
Box::new(|cc| Box::new(ComfyUiFrontend::new(cc))),
)
}