feat(server): report generation stages independently of previews (#2303)

Co-authored-by: Maxime Dréan <maximedrean@proton.me>
This commit is contained in:
leejetandMaxime Dréan authored and GitHub committed 2026-11-09 02:32:27 +08:00
1 parent b43ce4badd
commit fc350be2ce
12 files changed
+259 -11

No files matched your search

+8
View File
@@ -1807,6 +1807,7 @@ void StableDiffusionGGML::lora_stat() {
}
bool StableDiffusionGGML::apply_loras(const sd_lora_t* loras, uint32_t lora_count) {
generation_progress.report("preparing", "loras");
std::vector<ModelManager::LoraSpec> all_loras;
all_loras.reserve(lora_count);
for (uint32_t i = 0; i < lora_count; i++) {
@@ -2243,6 +2244,7 @@ void StableDiffusionGGML::report_sample_progress(int step,
? (now - *last_progress_us) / 1000000.f
: 0.f;
pretty_progress(showstep, (int)total_steps, step_seconds);
generation_progress.report_sample(showstep, static_cast<int64_t>(total_steps));
if (last_progress_us != nullptr) {
*last_progress_us = now;
}
@@ -2424,6 +2426,9 @@ sd::Tensor<float> StableDiffusionGGML::sample(const std::shared_ptr<DiffusionMod
int64_t last_progress_us = ggml_time_us();
sd_begin_preview_pass(static_cast<int>(steps));
generation_progress.begin_sample(static_cast<int64_t>(steps),
work_diffusion_model == high_noise_diffusion_model ? "high_noise" : high_noise_diffusion_model != nullptr ? "low_noise"
: "");
SamplePreviewContext preview = prepare_sample_preview_context();
sd::Tensor<float> processed_init_latent = denoiser->process_latent_in(init_latent);
@@ -2995,6 +3000,7 @@ int StableDiffusionGGML::align_video_frames(int frames) {
}
sd::Tensor<float> StableDiffusionGGML::encode_to_vae_latents(const sd::Tensor<float>& x) {
generation_progress.report("vae_encode");
auto latents = first_stage_model->encode(n_threads, x, vae_tiling_params, circular_x, circular_y);
if (latents.empty()) {
return {};
@@ -3015,6 +3021,7 @@ sd::Tensor<float> StableDiffusionGGML::encode_first_stage(const sd::Tensor<float
}
sd::Tensor<float> StableDiffusionGGML::decode_first_stage(const sd::Tensor<float>& x, bool decode_video) {
generation_progress.report("vae_decode");
if (sd_version_is_pid(version) || sd_version_is_minit2i(version) || version == VERSION_IRIS) {
return sd::ops::clamp((x + 1.f) * 0.5f, 0.0f, 1.0f);
}
@@ -3069,6 +3076,7 @@ sd::Tensor<float> StableDiffusionGGML::decode_ltx_audio_latent(const sd::Tensor<
if (audio_vae_model == nullptr || audio_latent.empty()) {
return {};
}
generation_progress.report("audio_decode");
auto waveform = audio_vae_model->decode(n_threads, audio_latent);
return waveform;
}
+5
View File
@@ -21,6 +21,7 @@
#include "model/adapter/lora.hpp"
#include "model_builders.h"
#include "model_manager.h"
#include "runtime/generation_progress.h"
#include "stable-diffusion.h"
class RNG;
@@ -199,6 +200,7 @@ public:
std::unique_ptr<ConditioningCache> conditioning_cache_;
std::vector<ModelManager::LoraSpec> conditioning_loras_;
bool executing_ = false;
sd::GenerationProgress generation_progress;
std::shared_ptr<Denoiser> denoiser;
std::vector<float> file_alphas_cumprod;
@@ -254,6 +256,9 @@ public:
explicit ExecutionScope(StableDiffusionGGML& sd)
: operation(sd) {
if (operation.acquired) {
sd.generation_progress.report("preparing");
}
ready = operation.acquired && sd.refresh_model_sources();
}
+8 -1
View File
@@ -531,6 +531,7 @@ namespace sd::pipeline {
condition_params.ref_image_params = ref_image_params;
sd->generation_progress.report("conditioning", "extensions");
sd->prepare_generation_extensions(request->pm_params,
request->pulid_params,
condition_params,
@@ -538,7 +539,8 @@ namespace sd::pipeline {
sd->compute_ip_adapter_tokens(sd_img_gen_params->ip_adapter_image, sd_img_gen_params->ip_adapter_strength);
int64_t prepare_start_ms = ggml_time_ms();
condition_params.zero_out_masked = false;
auto cond = sd->get_learned_condition(condition_params);
sd->generation_progress.report("conditioning", "positive_prompt");
auto cond = sd->get_learned_condition(condition_params);
if (cond.empty()) {
LOG_ERROR("failed to encode prompt");
return std::nullopt;
@@ -584,6 +586,7 @@ namespace sd::pipeline {
// Keep source latents in CFG, but omit source images from the text encoder.
condition_params.ref_images = nullptr;
}
sd->generation_progress.report("conditioning", "negative_prompt");
uncond = sd->get_learned_condition(condition_params);
if (uncond.empty()) {
LOG_ERROR("failed to encode negative prompt");
@@ -615,6 +618,7 @@ namespace sd::pipeline {
if (use_ref_latent_img_cfg) {
condition_params.ref_images = &empty_ref_images;
}
sd->generation_progress.report("conditioning", "image_condition");
img_uncond = sd->get_learned_condition(condition_params);
if (img_uncond.empty()) {
LOG_ERROR("failed to encode image guidance prompt");
@@ -830,6 +834,7 @@ namespace sd::pipeline {
return {};
}
sd->generation_progress.report("upscaling", "hires");
sd::Tensor<float> upscaled_tensor;
if (request.hires.upscaler == SD_HIRES_UPSCALER_MODEL) {
upscaled_tensor = upscaler->upscale_tensor(decoded);
@@ -930,6 +935,7 @@ namespace sd::pipeline {
ImageVaeAxesGuard axes_guard(sd, sd_img_gen_params, request);
SamplePlan plan(sd, sd_img_gen_params, request);
sd->generation_progress.report("preparing", "inputs");
auto latents_opt = prepare_image_generation_latents(sd,
sd_img_gen_params,
&request,
@@ -1027,6 +1033,7 @@ namespace sd::pipeline {
}
LOG_INFO("hires fix: upscaling to %dx%d", request.hires.target_width, request.hires.target_height);
sd->generation_progress.report("upscaling", "hires");
std::unique_ptr<UpscalerGGML> hires_upscaler;
if (request.hires.upscaler == SD_HIRES_UPSCALER_MODEL) {
if (sd->get_cancel_flag() == SD_CANCEL_ALL) {
+6 -2
View File
@@ -1210,7 +1210,8 @@ namespace sd::pipeline {
condition_params.ref_image_params = ref_image_params;
int64_t prepare_start_ms = ggml_time_ms();
embeds.cond = sd->get_learned_condition(condition_params);
sd->generation_progress.report("conditioning", "positive_prompt");
embeds.cond = sd->get_learned_condition(condition_params);
if (embeds.cond.empty()) {
LOG_ERROR("failed to encode video prompt");
return std::nullopt;
@@ -1235,7 +1236,8 @@ namespace sd::pipeline {
}
if (request.use_uncond) {
condition_params.text = request.negative_prompt;
embeds.uncond = sd->get_learned_condition(condition_params);
sd->generation_progress.report("conditioning", "negative_prompt");
embeds.uncond = sd->get_learned_condition(condition_params);
if (embeds.uncond.empty()) {
LOG_ERROR("failed to encode negative video prompt");
return std::nullopt;
@@ -1901,6 +1903,7 @@ namespace sd::pipeline {
sd->reset_generation_extensions();
SamplePlan plan(sd, sd_vid_gen_params, request);
sd->generation_progress.report("preparing", "inputs");
auto latent_inputs_opt = prepare_video_generation_latents(sd, sd_vid_gen_params, &request, ref_image_params);
if (!latent_inputs_opt.has_value()) {
return false;
@@ -2029,6 +2032,7 @@ namespace sd::pipeline {
LOG_ERROR("cancelling generation before latent upscale");
return false;
}
sd->generation_progress.report("upscaling", "hires");
int64_t upscale_start = ggml_time_ms();
sd::Tensor<float> upscaled_latent;
if (sd_version_is_ltxav(sd->version)) {
+42
View File
@@ -0,0 +1,42 @@
#ifndef __SD_RUNTIME_GENERATION_PROGRESS_H__
#define __SD_RUNTIME_GENERATION_PROGRESS_H__
#include "stable-diffusion.h"
namespace sd {
class GenerationProgress {
sd_generation_progress_cb_t callback_ = nullptr;
void* data_ = nullptr;
int sample_pass_ = 0;
const char* sample_detail_ = "";
public:
void set_callback(sd_generation_progress_cb_t callback, void* data) {
callback_ = callback;
data_ = data;
sample_pass_ = 0;
sample_detail_ = "";
}
void report(const char* stage, const char* detail = "", int64_t completed = 0, int64_t total = 0, const char* unit = "") const {
if (callback_ != nullptr) {
const sd_generation_progress_t progress{stage, detail, unit, sample_pass_, completed, total};
callback_(&progress, data_);
}
}
void begin_sample(int64_t total, const char* detail) {
++sample_pass_;
sample_detail_ = detail;
report_sample(0, total);
}
void report_sample(int64_t completed, int64_t total) const {
report("sampling", sample_detail_, completed, total, "steps");
}
};
} // namespace sd
#endif // __SD_RUNTIME_GENERATION_PROGRESS_H__
+10
View File
@@ -698,6 +698,16 @@ struct sd_ctx_t {
StableDiffusionGGML* sd = nullptr;
};
void sd_set_generation_progress_callback(sd_ctx_t* ctx, sd_generation_progress_cb_t cb, void* data) {
if (ctx == nullptr || ctx->sd == nullptr) {
return;
}
std::lock_guard<std::recursive_mutex> lock(ctx->sd->execution_mutex);
if (!ctx->sd->executing_) {
ctx->sd->generation_progress.set_callback(cb, data);
}
}
sd_ctx_t* new_sd_ctx(const sd_ctx_params_t* sd_ctx_params) {
sd_ctx_t* sd_ctx = (sd_ctx_t*)malloc(sizeof(sd_ctx_t));
if (sd_ctx == nullptr) {