fix some issues with the preview image: Preview generation is disabled by default and only done when requested

Cleared stale generation state at job start/end.
Fixed the animated preview GIF buffer leak.
This commit is contained in:
Concedo
2026-08-07 00:19:39 +08:00
parent e3cb5e9e44
commit 61bfce83de
4 changed files with 75 additions and 18 deletions
+4
View File
@@ -221,6 +221,10 @@ extern "C"
{
return sdtype_get_ongoing_generation_info();
}
void sd_request_ongoing_generation_preview()
{
sdtype_request_ongoing_generation_preview();
}
bool whisper_load_model(const whisper_load_model_inputs inputs)
{
+24 -4
View File
@@ -1003,6 +1003,8 @@ def init_library():
handle.sd_abort_generation.restype = None
handle.sd_get_ongoing_generation_info.argtypes = []
handle.sd_get_ongoing_generation_info.restype = sd_info_outputs
handle.sd_request_ongoing_generation_preview.argtypes = []
handle.sd_request_ongoing_generation_preview.restype = None
handle.whisper_load_model.argtypes = [whisper_load_model_inputs]
handle.whisper_load_model.restype = ctypes.c_bool
handle.whisper_generate.argtypes = [whisper_generation_inputs]
@@ -2979,11 +2981,26 @@ def sd_get_ongoing_generation_info():
try:
return json.loads(info.data)
except Exception:
print("An error occurred while decoding sd ongoig generation info")
print("An error occurred while decoding sd ongoing generation info")
else:
print("An error occurred while getting sd ongoig generation info")
print("An error occurred while getting sd ongoing generation info")
return {}
def parse_query_bool(parsed_dict, key, default=False):
value = parsed_dict.get(key, [default])
if isinstance(value, list):
value = value[0] if value else default
if isinstance(value, bool):
return value
if value is None:
return default
value = str(value).strip().lower()
if value in ('1', 'true', 'yes', 'on'):
return True
if value in ('0', 'false', 'no', 'off'):
return False
return default
def build_a1111_progress_response(
status: str,
step_count: int = 0,
@@ -3061,12 +3078,14 @@ def build_a1111_progress_response(
}
def a1111_progress_response(preview=False):
if preview:
handle.sd_request_ongoing_generation_preview()
status = sd_get_ongoing_generation_info()
result = build_a1111_progress_response(
status.get('status', 0),
status.get('step', 0),
status.get('steps', 1),
status.get('step_time', 1),
status.get('elapsed_time', 0),
preview and status.get('preview') or None)
return result
@@ -6584,7 +6603,7 @@ Change Mode<br>
parsed_url = urllib.parse.urlparse(self.path)
parsed_dict = urllib.parse.parse_qs(parsed_url.query)
genkey = parsed_dict.get('genkey', [''])[0]
skip_current_image = bool(parsed_dict.get('skip_current_image', False))
skip_current_image = parse_query_bool(parsed_dict, 'skip_current_image')
# with no auth, reveal status without preview image
auth = bool(genkey and genkey==currgenimgkey)
info = a1111_progress_response(auth and not skip_current_image)
@@ -7731,6 +7750,7 @@ Change Mode<br>
self.end_headers(content_type='application/json')
self.wfile.write(genresp)
except Exception as ex:
currgenimgkey = ''
utfprint(ex,1)
print("Generate Image: The response could not be sent, maybe connection was terminated?")
time.sleep(0.2) #short delay
+1
View File
@@ -113,6 +113,7 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs);
sd_generation_outputs sdtype_upscale(const sd_upscale_inputs inputs);
sd_info_outputs sdtype_get_info();
sd_info_outputs sdtype_get_ongoing_generation_info();
void sdtype_request_ongoing_generation_preview();
void sdtype_abort_generation();
bool whispertype_load_model(const whisper_load_model_inputs inputs);
+46 -14
View File
@@ -161,16 +161,17 @@ static bool is_vid_model = false;
static bool remove_limits = false;
struct gendata_st {
int status;
int step;
double step_time;
int status = 0;
int step = 0;
double step_time = 0.0;
std::string preview;
};
struct {
std::mutex mux;
std::chrono::steady_clock::time_point start_time;
int steps;
int steps = 0;
bool preview_requested = false;
gendata_st gendata;
} geninfo;
@@ -574,7 +575,7 @@ bool sdtype_load_model(const sd_load_model_inputs inputs) {
}
}
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, true, false, nullptr);
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, false, false, nullptr);
if (sddebugmode) {
// the default progress bar would become intermingled with the debug log
@@ -1028,8 +1029,12 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs)
{
struct CleanupInfoOnExit {
~CleanupInfoOnExit() {
std::lock_guard<std::mutex> lock(geninfo.mux);
geninfo.gendata.status = 0;
{
std::lock_guard<std::mutex> lock(geninfo.mux);
geninfo.gendata.status = 0;
geninfo.preview_requested = false;
}
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, false, false, nullptr);
}
} cleanup_info_on_exit;
@@ -1041,9 +1046,12 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs)
{
std::lock_guard<std::mutex> lock(geninfo.mux);
geninfo.start_time = std::chrono::steady_clock::now();
geninfo.gendata.status = 1;
geninfo.steps = inputs.sample_steps;
geninfo.preview_requested = false;
geninfo.gendata = {};
geninfo.gendata.status = 1;
}
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, false, false, nullptr);
sd_image_t * results = nullptr;
int generated_num_results = 0;
@@ -1730,6 +1738,15 @@ static inline double get_time_delta(const std::chrono::steady_clock::time_point&
static void step_callback(int step, int frame_count, sd_image_t* image, bool is_noisy, void* data)
{
{
std::lock_guard<std::mutex> lock(geninfo.mux);
if (!geninfo.preview_requested) {
return;
}
geninfo.preview_requested = false;
}
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, false, false, nullptr);
gendata_st gendata;
gendata.status = 2;
if (frame_count == 1) {
@@ -1737,8 +1754,12 @@ static void step_callback(int step, int frame_count, sd_image_t* image, bool is_
} else {
uint8_t * out_data = nullptr;
size_t out_len = 0;
create_gif_buf_from_sd_images_msf(image, frame_count, 16, &out_data,&out_len);
gendata.preview = kcpp_base64_encode(out_data, out_len);
if (create_gif_buf_from_sd_images_msf(image, frame_count, 16, &out_data,&out_len) == 0 && out_data && out_len > 0) {
gendata.preview = kcpp_base64_encode(out_data, out_len);
}
if (out_data) {
free(out_data);
}
}
gendata.step = step;
gendata.step_time = get_time_delta(geninfo.start_time);
@@ -1749,6 +1770,15 @@ static void step_callback(int step, int frame_count, sd_image_t* image, bool is_
geninfo.gendata = gendata;
}
void sdtype_request_ongoing_generation_preview()
{
std::lock_guard<std::mutex> lock(geninfo.mux);
if (geninfo.gendata.status != 0) {
geninfo.preview_requested = true;
sd_set_preview_callback(step_callback, PREVIEW_PROJ, 1, true, false, nullptr);
}
}
sd_generation_outputs sdtype_upscale(const sd_upscale_inputs inputs)
{
sd_generation.reset();
@@ -1843,14 +1873,16 @@ sd_info_outputs sdtype_get_info()
sd_info_outputs sdtype_get_ongoing_generation_info()
{
double elapsed_time;
int steps;
double elapsed_time = 0.0;
int steps = 0;
gendata_st gendata;
{
std::lock_guard<std::mutex> lock(geninfo.mux);
gendata = geninfo.gendata;
elapsed_time = get_time_delta(geninfo.start_time);
steps = geninfo.steps;
if (gendata.status != 0) {
elapsed_time = get_time_delta(geninfo.start_time);
}
}
nlohmann::json j;
@@ -1868,7 +1900,7 @@ sd_info_outputs sdtype_get_ongoing_generation_info()
j["status"] = "idle";
j["preview"] = gendata.preview;
static std::string recent_info;
static thread_local std::string recent_info;
recent_info = j.dump();
sd_info_outputs output;
output.status = 0;