diff --git a/embd_res/kcpp_docs.embd b/embd_res/kcpp_docs.embd index 343b45b30..5dbc27336 100644 --- a/embd_res/kcpp_docs.embd +++ b/embd_res/kcpp_docs.embd @@ -2557,6 +2557,64 @@ ] } }, + "/sdapi/v1/upscale": { + "post": { + "description": "Upscales an image with ESRGAN, increasing its resolution.", + "requestBody": { + "content": { + "application/json": { + "example": { + "image": "base64_image_data", + "upscaling_resize": 2 + }, + "schema": { + "properties": { + "image": { + "type": "string", + "description": "A base64 string containing the encoded PNG of the image." + }, + "upscaling_resize": { + "type": "integer", + "description": "Integer upscale factor. Defaults to 2." + }, + }, + "type": "object" + } + } + }, + "required": false + }, + "responses": { + "200": { + "content": { + "application/json": { + "example": + { + "html_info":"string","image":"base64_image_data" + }, + "schema": { + "properties": { + "html_info": { + "type": "string", + "description": "Not important." + }, + "image": { + "type": "string", + "description": "Base64 encoded image data" + } + } + } + } + }, + "description": "Successful request" + } + }, + "summary": "Upscales an image with ESRGAN, increasing its resolution.", + "tags": [ + "sdapi/v1" + ] + } + }, "/v1/completions": { "post": { "summary": "Generates text continuations given a prompt. Please refer to OpenAI documentation", diff --git a/embd_res/kcpp_sdui.embd b/embd_res/kcpp_sdui.embd index 68cebafe4..c0e2cc451 100644 --- a/embd_res/kcpp_sdui.embd +++ b/embd_res/kcpp_sdui.embd @@ -5,18 +5,18 @@ Stable UI for KoboldCpp - diff --git a/expose.h b/expose.h index d0f056e1f..432b379d8 100644 --- a/expose.h +++ b/expose.h @@ -225,6 +225,7 @@ struct sd_generation_inputs const bool remove_limits = false; const bool circular_x = false; const bool circular_y = false; + const bool upscale = false; }; struct sd_generation_outputs { diff --git a/koboldcpp.py b/koboldcpp.py index 5a1292d31..fadeca166 100755 --- a/koboldcpp.py +++ b/koboldcpp.py @@ -348,7 +348,8 @@ class sd_generation_inputs(ctypes.Structure): ("video_output_type", ctypes.c_int), ("remove_limits", ctypes.c_bool), ("circular_x", ctypes.c_bool), - ("circular_y", ctypes.c_bool)] + ("circular_y", ctypes.c_bool), + ("upscale", ctypes.c_bool)] class sd_generation_outputs(ctypes.Structure): _fields_ = [("status", ctypes.c_int), @@ -2200,6 +2201,7 @@ def sd_generate(genparams): inputs.remove_limits = allow_remove_limits inputs.circular_x = tryparseint(adapter_obj.get("circular_x", genparams.get("circular_x",0)),0) inputs.circular_y = tryparseint(adapter_obj.get("circular_y", genparams.get("circular_y",0)),0) + inputs.upscale = (True if tryparseint(genparams.get("enable_hr", 0),0) else False) ret = handle.sd_generate(inputs) data_main = "" data_extra = "" @@ -6400,7 +6402,7 @@ def show_gui(): makefileentry(images_tab, "Clip-1 File:", "Select First Clip model file (Clip-L for SD3 or Flux, or other vision encoder)",sd_clip1_var, 26, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf","*.safetensors *.gguf")],tooltiptxt="Select a .safetensors Clip-1 file to be loaded.\nThis is Clip-L for SD3 and Flux, Clip Vision for WAN, and Qwen2.5VL for QwenImage") makefileentry(images_tab, "Clip-2 File:", "Select Second Clip model file (Clip-G for SD3)",sd_clip2_var, 28, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf","*.safetensors *.gguf")],tooltiptxt="Select a .safetensors Clip-2 file to be loaded.\nThis is Clip-G for SD3") makefileentry(images_tab, "PhotoMaker:", "Select Optional PhotoMaker model file (SDXL)",sd_photomaker_var, 30, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf","*.safetensors *.gguf")],tooltiptxt="PhotoMaker is a model that allows face cloning.\nSelect a .safetensors PhotoMaker file to be loaded (SDXL only).") - makefileentry(images_tab, "Upscaler:", "Select Optional Upscaling model file (ESRGAN)",sd_upscaler_var, 32, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf","*.safetensors *.gguf")],tooltiptxt="Select an upscaler model file.\nCurrently only ESRGAN is supported.") + makefileentry(images_tab, "Upscaler:", "Select Optional Upscaling model file (ESRGAN)",sd_upscaler_var, 32, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf *.pth","*.safetensors *.gguf *.pth")],tooltiptxt="Select an upscaler model file.\nCurrently only ESRGAN is supported.") sdvaeitem1,sdvaeitem2,sdvaeitem3 = makefileentry(images_tab, "Image VAE:", "Select Optional SD VAE file",sd_vae_var, 40, width=280, singlerow=True, filetypes=[("*.safetensors *.gguf", "*.safetensors *.gguf")],tooltiptxt="Select a .safetensors or .gguf SD VAE file to be loaded.") @@ -8148,7 +8150,7 @@ def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False): if dlfile: args.sdphotomaker = dlfile if args.sdupscaler and args.sdupscaler!="": - dlfile = download_model_from_url(args.sdupscaler,[".gguf",".safetensors"],min_file_size=500000) + dlfile = download_model_from_url(args.sdupscaler,[".gguf",".safetensors",".pth"],min_file_size=500000) if dlfile: args.sdupscaler = dlfile if args.sdvae and args.sdvae!="": diff --git a/otherarch/sdcpp/model.cpp b/otherarch/sdcpp/model.cpp index c078ef57d..4cbc258cf 100644 --- a/otherarch/sdcpp/model.cpp +++ b/otherarch/sdcpp/model.cpp @@ -388,10 +388,9 @@ bool ModelLoader::init_from_file(const std::string& file_path, const std::string } else if (is_safetensors_file(file_path)) { LOG_INFO("load %s using safetensors format", file_path.c_str()); return init_from_safetensors_file(file_path, prefix); - //disable ckpt loading - // } else if (is_zip_file(file_path)) { - // LOG_INFO("load %s using checkpoint format", file_path.c_str()); - // return init_from_ckpt_file(file_path, prefix); + } else if (is_zip_file(file_path)) { + LOG_INFO("load %s using checkpoint format", file_path.c_str()); + return init_from_ckpt_file(file_path, prefix); } else { LOG_WARN("unknown format %s", file_path.c_str()); return false; diff --git a/otherarch/sdcpp/sdtype_adapter.cpp b/otherarch/sdcpp/sdtype_adapter.cpp index 6ccbb38b7..93b5d1883 100644 --- a/otherarch/sdcpp/sdtype_adapter.cpp +++ b/otherarch/sdcpp/sdtype_adapter.cpp @@ -98,11 +98,13 @@ int total_img_gens = 0; //global static vars for SD static SDParams * sd_params = nullptr; static sd_ctx_t * sd_ctx = nullptr; +static upscaler_ctx_t* upscaler_ctx = nullptr; static int sddebugmode = 0; static std::string recent_data = ""; static std::string recent_data2 = ""; //for cases when we have 2 outputs static uint8_t * input_image_buffer = NULL; static uint8_t * input_mask_buffer = NULL; +static uint8_t * upscale_src_buffer = NULL; static std::vector input_extraimage_buffers; const int max_extra_images = 4; @@ -432,6 +434,22 @@ bool sdtype_load_model(const sd_load_model_inputs inputs) { input_extraimage_buffers.reserve(max_extra_images); + //load upscaler if provided + if (upscaler_filename!="") { + const int upscale_tile_size = 128; + upscaler_ctx = new_upscaler_ctx(upscaler_filename.c_str(), + params.offload_params_to_cpu, + params.diffusion_conv_direct, + params.n_threads, + upscale_tile_size); + + if (upscaler_ctx == nullptr) { + printf("\nError: KCPP failed to load upscaler!\n"); + } else { + printf("\nUpscaler has been loaded.\n"); + } + } + return true; } @@ -1175,6 +1193,8 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs) } bool wasanim = false; + sd_image_t upscaled_image; + upscaled_image.data = nullptr; for (int i = 0; i < params.batch_count; i++) { if (results[i].data == NULL) { @@ -1234,7 +1254,16 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs) else { int out_data_len; - unsigned char * png = stbi_write_png_to_mem(results[i].data, 0, results[i].width, results[i].height, results[i].channel, &out_data_len, get_image_params(params).c_str()); + unsigned char * png = nullptr; + if(inputs.upscale && upscaler_ctx != nullptr) + { + printf("Upscaling output image...\n"); + upscaled_image = upscale(upscaler_ctx, results[i], 2); + png = stbi_write_png_to_mem(upscaled_image.data, 0, upscaled_image.width, upscaled_image.height, upscaled_image.channel, &out_data_len, get_image_params(params).c_str()); + } else { + png = stbi_write_png_to_mem(results[i].data, 0, results[i].width, results[i].height, results[i].channel, &out_data_len, get_image_params(params).c_str()); + } + if (png != NULL) { recent_data = kcpp_base64_encode(png,out_data_len); @@ -1247,6 +1276,12 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs) results[i].data = NULL; } + if(upscaled_image.data) + { + free(upscaled_image.data); + upscaled_image.data = nullptr; + } + free(results); output.data = recent_data.c_str(); output.data_extra = recent_data2.c_str(); @@ -1259,9 +1294,13 @@ sd_generation_outputs sdtype_generate(const sd_generation_inputs inputs) sd_generation_outputs sdtype_upscale(const sd_upscale_inputs inputs) { sd_generation_outputs output; - if(sd_ctx == nullptr || sd_params == nullptr) + output.data = ""; + output.data_extra = ""; + output.animated = 0; + output.status = 0; + if(sd_ctx == nullptr || upscaler_ctx == nullptr || sd_params == nullptr) { - printf("\nWarning: KCPP image generation not initialized!\n"); + printf("\nWarning: KCPP image upscaling not initialized!\n"); output.data = ""; output.data_extra = ""; output.animated = 0; @@ -1269,7 +1308,42 @@ sd_generation_outputs sdtype_upscale(const sd_upscale_inputs inputs) return output; } - return output; + std::string rawb64 = inputs.init_images; + int nx, ny; + if(upscale_src_buffer!=nullptr) //just in time free old buffer + { + stbi_image_free(upscale_src_buffer); + upscale_src_buffer = nullptr; + } + upscale_src_buffer = load_image_from_b64(rawb64,nx,ny); + sd_image_t source_img; + sd_image_t upscaled_image; + source_img.data = nullptr; + upscaled_image.data = nullptr; + if(upscale_src_buffer) + { + source_img.width = nx; + source_img.height = ny; + source_img.channel = 3; + source_img.data = upscale_src_buffer; + + upscaled_image = upscale(upscaler_ctx, source_img, inputs.upscaling_resize); + int out_data_len; + unsigned char * png = stbi_write_png_to_mem(upscaled_image.data, 0, upscaled_image.width, upscaled_image.height, upscaled_image.channel, &out_data_len, nullptr); + if (png != NULL) + { + recent_data = kcpp_base64_encode(png,out_data_len); + recent_data2 = ""; + free(png); + } + free(upscaled_image.data); + output.data = recent_data.c_str(); + output.data_extra = recent_data2.c_str(); + output.animated = 0; + output.status = 1; + } + + return output; } sd_info_outputs sdtype_get_info()