From 61bfce83de55fc2de095af34832dd9ac229e0d72 Mon Sep 17 00:00:00 2001 From: Concedo <39025047+LostRuins@users.noreply.github.com> Date: Fri, 7 Aug 2026 00:19:39 +0800 Subject: [PATCH] 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. --- expose.cpp | 4 ++ koboldcpp.py | 28 ++++++++++++-- model_adapter.h | 1 + otherarch/sdcpp/sdtype_adapter.cpp | 60 +++++++++++++++++++++++------- 4 files changed, 75 insertions(+), 18 deletions(-) diff --git a/expose.cpp b/expose.cpp index 5ca4a7813..822e9c12f 100644 --- a/expose.cpp +++ b/expose.cpp @@ -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) { diff --git a/koboldcpp.py b/koboldcpp.py index 604aabe88..57f72ec78 100644 --- a/koboldcpp.py +++ b/koboldcpp.py @@ -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
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
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 diff --git a/model_adapter.h b/model_adapter.h index d4b144533..e2711b0c3 100644 --- a/model_adapter.h +++ b/model_adapter.h @@ -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); diff --git a/otherarch/sdcpp/sdtype_adapter.cpp b/otherarch/sdcpp/sdtype_adapter.cpp index d0b57f14e..107a4d09b 100644 --- a/otherarch/sdcpp/sdtype_adapter.cpp +++ b/otherarch/sdcpp/sdtype_adapter.cpp @@ -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 lock(geninfo.mux); - geninfo.gendata.status = 0; + { + std::lock_guard 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 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 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 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 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;