From cdd6578a9a51b636dbacc74715b9b2f90d34cf35 Mon Sep 17 00:00:00 2001
From: Concedo <39025047+LostRuins@users.noreply.github.com>
Date: Tue, 20 Jan 2026 22:10:37 +0800
Subject: [PATCH] esrgan added
---
embd_res/kcpp_docs.embd | 58 ++++++++++++
embd_res/kcpp_sdui.embd | 138 ++++++++++++++---------------
expose.h | 1 +
koboldcpp.py | 8 +-
otherarch/sdcpp/model.cpp | 7 +-
otherarch/sdcpp/sdtype_adapter.cpp | 82 ++++++++++++++++-
6 files changed, 214 insertions(+), 80 deletions(-)
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()