use std::process::Command;
use crate::tasks::generate_image::{GenerateImageRequest, GenerateImageResult};
use crate::InferenceError;
const CLI_BINARY: &str = "mflux-generate";
const DEFAULT_MODEL: &str = "mlx-community/Flux-1.lite-8B-MLX-Q4";
const DEFAULT_BASE_MODEL: &str = "dev";
pub fn is_available() -> bool {
Command::new(CLI_BINARY)
.arg("--help")
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
pub fn generate_image(req: &GenerateImageRequest) -> Result<GenerateImageResult, InferenceError> {
let output_path = req
.output_path
.clone()
.unwrap_or_else(|| "output.png".to_string());
let mut cmd = Command::new(CLI_BINARY);
cmd.arg("--base-model")
.arg(DEFAULT_BASE_MODEL)
.arg("--model")
.arg(req.model.as_deref().unwrap_or(DEFAULT_MODEL))
.arg("--prompt")
.arg(&req.prompt)
.arg("--output")
.arg(&output_path);
if let Some(w) = req.width {
cmd.arg("--width").arg(w.to_string());
}
if let Some(h) = req.height {
cmd.arg("--height").arg(h.to_string());
}
if let Some(s) = req.steps {
cmd.arg("--steps").arg(s.to_string());
}
if let Some(g) = req.guidance {
cmd.arg("--guidance").arg(g.to_string());
}
if let Some(seed) = req.seed {
cmd.arg("--seed").arg(seed.to_string());
}
tracing::info!(prompt = %req.prompt, output = %output_path, "external mflux: invoking");
let output = cmd.output().map_err(|e| {
InferenceError::InferenceFailed(format!(
"failed to spawn `{CLI_BINARY}`: {e}. \
Install with `uv pip install mflux` and put its venv's bin on PATH."
))
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(InferenceError::InferenceFailed(format!(
"mflux-generate exited with status {}: stderr={stderr}",
output.status
)));
}
Ok(GenerateImageResult {
image_path: output_path,
media_type: "image/png".to_string(),
model_used: Some(format!(
"external:{}",
req.model.as_deref().unwrap_or(DEFAULT_MODEL)
)),
})
}