comfyui compat - serve temporary upload endpoint for img2img

This commit is contained in:
Concedo 2025-06-16 23:18:47 +08:00
parent 6c9654f744
commit ab29be54c4
2 changed files with 214 additions and 61 deletions

View file

@ -12,7 +12,7 @@ Current version indicated by LITEVER below.
--> -->
<script> <script>
const LITEVER = 254; const LITEVER = 255;
const urlParams = new URLSearchParams(window.location.search); const urlParams = new URLSearchParams(window.location.search);
var localflag = urlParams.get('local'); //this will be replaced automatically in embedded kcpp var localflag = urlParams.get('local'); //this will be replaced automatically in embedded kcpp
const STORAGE_PREFIX = (localflag?"e_":"")+"kaihordewebui_"; const STORAGE_PREFIX = (localflag?"e_":"")+"kaihordewebui_";
@ -3032,6 +3032,7 @@ Current version indicated by LITEVER below.
const default_oai_image_endpoint = "/images/generations"; const default_oai_image_endpoint = "/images/generations";
const default_oai_tts_endpoint = "/audio/speech"; const default_oai_tts_endpoint = "/audio/speech";
const default_oai_embeddings_endpoint = "/embeddings";
const default_dalle_model_name = "dall-e-3"; const default_dalle_model_name = "dall-e-3";
const claude_submit_endpoint = "/complete"; const claude_submit_endpoint = "/complete";
@ -3059,6 +3060,7 @@ Current version indicated by LITEVER below.
const comfy_generate_endpoint = "/prompt"; const comfy_generate_endpoint = "/prompt";
const comfy_history_endpoint = "/history"; const comfy_history_endpoint = "/history";
const comfy_results_endpoint = "/view?filename="; const comfy_results_endpoint = "/view?filename=";
const comfy_upload_endpoint = "/api/upload/image";
const xtts_gen_endpoint = "/tts_to_audio/"; const xtts_gen_endpoint = "/tts_to_audio/";
const xtts_voices_endpoint = "/speakers_list"; const xtts_voices_endpoint = "/speakers_list";
@ -3136,13 +3138,12 @@ Current version indicated by LITEVER below.
var current_wi = []; //each item stores a wi object. var current_wi = []; //each item stores a wi object.
var wi_insertlocation = 0; //after memory var wi_insertlocation = 0; //after memory
var wi_searchdepth = 0; //search everything var wi_searchdepth = 0; //search everything
var documentdb_enabled = false; var documentdb_provider = 0; //0 = disables, 1 = textdb, 2 = kcpp, 3 = openai embeddings
var documentdb_searchhistory = false; var documentdb_searchhistory = false;
var documentdb_numresults = 3; var documentdb_numresults = 3;
var documentdb_searchrange = 300; var documentdb_searchrange = 300;
var documentdb_chunksize = 800; var documentdb_chunksize = 800;
var documentdb_data = ""; var documentdb_data = "";
var documentdb_useembeddings = false
var generateimagesinterval = 750; //if generated images is enabled, it will trigger after every 700 new characters in context. var generateimagesinterval = 750; //if generated images is enabled, it will trigger after every 700 new characters in context.
var nextgeneratedimagemilestone = generateimagesinterval; //used to keep track of when to generate the next image var nextgeneratedimagemilestone = generateimagesinterval; //used to keep track of when to generate the next image
var image_db = {}; //stores a dictionary of pending images var image_db = {}; //stores a dictionary of pending images
@ -3246,6 +3247,8 @@ Current version indicated by LITEVER below.
saved_dalle_model: default_dalle_model_name, saved_dalle_model: default_dalle_model_name,
saved_oai_tts_key: "", saved_oai_tts_key: "",
saved_oai_tts_url: (default_oai_base + "/v1" + default_oai_tts_endpoint), saved_oai_tts_url: (default_oai_base + "/v1" + default_oai_tts_endpoint),
saved_oai_embd_key: "",
saved_oai_embd_url: (default_oai_base + "/v1" + default_oai_embeddings_endpoint),
saved_openrouter_key: "", saved_openrouter_key: "",
saved_mistralai_key: "", saved_mistralai_key: "",
saved_featherless_key: "", saved_featherless_key: "",
@ -3365,6 +3368,7 @@ Current version indicated by LITEVER below.
render_streaming_markdown: true, render_streaming_markdown: true,
raw_instruct_tags: false, //experimental flag raw_instruct_tags: false, //experimental flag
show_endpoint_selector: false, show_endpoint_selector: false,
never_rewind_ctx: false,
//section migrated from story itself //section migrated from story itself
extrastopseq: "", extrastopseq: "",
@ -6416,11 +6420,37 @@ Current version indicated by LITEVER below.
}); });
} }
function uploadBase64ImgToComfy(base64Data,filename) {
if (base64Data==null || base64Data == '') {
return Promise.resolve(); //return instantly
}
let upload_endpoint = localsettings.saved_comfy_url + comfy_upload_endpoint;
const binary = atob(base64Data);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
const blob = new Blob([bytes], { type: 'image/jpeg' });
const formData = new FormData();
formData.append('image', blob, filename);
formData.append('overwrite',1);
return fetch(`${upload_endpoint}`, {
method: 'POST',
body: formData,
}).then(response => {
if (!response.ok) {
throw new Error(`Upload failed with status ${response.status}`);
}
return response;
});
}
function generate_comfy_image(req_payload, autoappend) function generate_comfy_image(req_payload, autoappend)
{ {
let splits = req_payload.prompt.split("###"); let splits = req_payload.prompt.split("###");
let prompt = splits[0].trim(); let prompt = splits[0].trim();
let negprompt = (splits.length > 1 ? splits[1] : ""); let negprompt = (splits.length > 1 ? splits[1] : "");
let comfyimg2imgname = 'kcpp_img2img.jpg';
let genimg_payload = { let genimg_payload = {
"prompt": { "prompt": {
@ -6484,6 +6514,25 @@ Current version indicated by LITEVER below.
} }
}; };
if(req_payload["source_image"]) //override with img2img nodes
{
genimg_payload["prompt"]["5"] = {
"class_type": "LoadImage",
"inputs": {
"image": comfyimg2imgname
}
};
genimg_payload["prompt"]["10"] = {
"class_type": "VAEEncode",
"inputs": {
"pixels": ["5", 0],
"vae": ["4", 2]
}
};
genimg_payload["prompt"]["3"]["inputs"]["latent_image"] = ["10", 0];
genimg_payload["prompt"]["3"]["inputs"]["denoise"] = req_payload["params"]["denoising_strength"];
}
let gen_endpoint = localsettings.saved_comfy_url + comfy_generate_endpoint; let gen_endpoint = localsettings.saved_comfy_url + comfy_generate_endpoint;
console.log(genimg_payload); console.log(genimg_payload);
let imgid = "Comfyimg"+(Math.floor(10000 + Math.random() * 90000)).toString(); let imgid = "Comfyimg"+(Math.floor(10000 + Math.random() * 90000)).toString();
@ -6507,6 +6556,7 @@ Current version indicated by LITEVER below.
image_db[imgid].imsource = 0; //0=generated,1=uploaded image_db[imgid].imsource = 0; //0=generated,1=uploaded
image_db[imgid].imrefid = ""; image_db[imgid].imrefid = "";
uploadBase64ImgToComfy(req_payload["source_image"],comfyimg2imgname).then(() => {
fetch(gen_endpoint, { fetch(gen_endpoint, {
method: 'POST', method: 'POST',
headers: { headers: {
@ -6528,6 +6578,10 @@ Current version indicated by LITEVER below.
console.log("Generation Error: " + error); console.log("Generation Error: " + error);
msgbox("Image Generation Failed!\n\nPlease make sure ComfyUI is running at "+localsettings.saved_comfy_url+" and properly configured!\n\nIt must be launched with the flag --listen --enable-cors-header '*' to enable API access\n"); msgbox("Image Generation Failed!\n\nPlease make sure ComfyUI is running at "+localsettings.saved_comfy_url+" and properly configured!\n\nIt must be launched with the flag --listen --enable-cors-header '*' to enable API access\n");
}); });
}).catch((error) => {
console.log("Upload Img2Img Error: " + error);
msgbox("Image Upload Failed!\n\nPlease make sure ComfyUI is running at "+localsettings.saved_comfy_url+" and properly configured!\n\nIt must be launched with the flag --listen --enable-cors-header '*' to enable API access\n");
});
return imgid; return imgid;
} }
@ -6795,6 +6849,29 @@ Current version indicated by LITEVER below.
},false); },false);
} }
function set_oai_embd_key()
{
inputBox("Enter OpenAI Compatible Embeddings API Key","OpenAI Compatible Embeddings API Key",localsettings.saved_oai_embd_key,"Input OpenAI Compatible Embeddings API Key", ()=>{
let userinput = getInputBoxValue();
userinput = userinput.trim();
if (userinput != null && userinput!="") {
localsettings.saved_oai_embd_key = userinput.trim();
}
},false,false,true);
}
function set_oai_embd_url()
{
inputBox("Enter OpenAI Compatible TTS API URL","OpenAI Compatible Embeddings API URL",localsettings.saved_oai_embd_url,"Input OpenAI Compatible Embeddings API URL", ()=>{
let userinput = getInputBoxValue();
userinput = userinput.trim();
if (userinput != null && userinput!="") {
localsettings.saved_oai_embd_url = userinput.trim();
}else{
localsettings.saved_oai_embd_url = (default_oai_base + "/v1" + default_oai_embeddings_endpoint);
}
},false);
}
function generate_dalle_image(req_payload, onImagesDone) function generate_dalle_image(req_payload, onImagesDone)
{ {
//split the prompt //split the prompt
@ -7304,13 +7381,12 @@ Current version indicated by LITEVER below.
new_save_storyobj.wisearchdepth = wi_searchdepth; new_save_storyobj.wisearchdepth = wi_searchdepth;
new_save_storyobj.wiinsertlocation = wi_insertlocation; new_save_storyobj.wiinsertlocation = wi_insertlocation;
new_save_storyobj.personal_notes = personal_notes; new_save_storyobj.personal_notes = personal_notes;
new_save_storyobj.documentdb_enabled = documentdb_enabled; new_save_storyobj.documentdb_provider = documentdb_provider;
new_save_storyobj.documentdb_searchhistory = documentdb_searchhistory; new_save_storyobj.documentdb_searchhistory = documentdb_searchhistory;
new_save_storyobj.documentdb_numresults = documentdb_numresults; new_save_storyobj.documentdb_numresults = documentdb_numresults;
new_save_storyobj.documentdb_searchrange = documentdb_searchrange; new_save_storyobj.documentdb_searchrange = documentdb_searchrange;
new_save_storyobj.documentdb_chunksize = documentdb_chunksize; new_save_storyobj.documentdb_chunksize = documentdb_chunksize;
new_save_storyobj.documentdb_data = documentdb_data; new_save_storyobj.documentdb_data = documentdb_data;
new_save_storyobj.documentdb_useembeddings = documentdb_useembeddings;
if (export_settings) { if (export_settings) {
new_save_storyobj.savedsettings = JSON.parse(JSON.stringify(localsettings)); new_save_storyobj.savedsettings = JSON.parse(JSON.stringify(localsettings));
@ -7596,9 +7672,9 @@ Current version indicated by LITEVER below.
if (storyobj.personal_notes) { if (storyobj.personal_notes) {
personal_notes = storyobj.personal_notes; personal_notes = storyobj.personal_notes;
} }
if(storyobj.documentdb_enabled) if(storyobj.documentdb_provider)
{ {
documentdb_enabled = storyobj.documentdb_enabled; documentdb_provider = storyobj.documentdb_provider;
} }
if(storyobj.documentdb_searchhistory) if(storyobj.documentdb_searchhistory)
{ {
@ -7620,11 +7696,6 @@ Current version indicated by LITEVER below.
{ {
documentdb_data = storyobj.documentdb_data; documentdb_data = storyobj.documentdb_data;
} }
if(storyobj.documentdb_useembeddings)
{
documentdb_useembeddings = storyobj.documentdb_useembeddings;
}
// adapting legacy fields - these are all now moved to SETTINGS // adapting legacy fields - these are all now moved to SETTINGS
if (storyobj.extrastopseq) { if (storyobj.extrastopseq) {
@ -7742,6 +7813,8 @@ Current version indicated by LITEVER below.
let tmp_oai4 = localsettings.saved_dalle_url; let tmp_oai4 = localsettings.saved_dalle_url;
let tmp_oai5 = localsettings.saved_oai_tts_key; let tmp_oai5 = localsettings.saved_oai_tts_key;
let tmp_oai6 = localsettings.saved_oai_tts_url; let tmp_oai6 = localsettings.saved_oai_tts_url;
let tmp_oai7 = localsettings.saved_oai_embd_key;
let tmp_oai8 = localsettings.saved_oai_embd_url;
let tmp_or1 = localsettings.saved_openrouter_key; let tmp_or1 = localsettings.saved_openrouter_key;
let tmp_mai = localsettings.saved_mistralai_key; let tmp_mai = localsettings.saved_mistralai_key;
let tmp_fai = localsettings.saved_featherless_key; let tmp_fai = localsettings.saved_featherless_key;
@ -7798,6 +7871,8 @@ Current version indicated by LITEVER below.
localsettings.saved_dalle_url = tmp_oai4; localsettings.saved_dalle_url = tmp_oai4;
localsettings.saved_oai_tts_key = tmp_oai5; localsettings.saved_oai_tts_key = tmp_oai5;
localsettings.saved_oai_tts_url = tmp_oai6; localsettings.saved_oai_tts_url = tmp_oai6;
localsettings.saved_oai_embd_key = tmp_oai7;
localsettings.saved_oai_embd_url = tmp_oai8;
localsettings.saved_openrouter_key = tmp_or1; localsettings.saved_openrouter_key = tmp_or1;
localsettings.saved_mistralai_key = tmp_mai; localsettings.saved_mistralai_key = tmp_mai;
localsettings.saved_featherless_key = tmp_fai; localsettings.saved_featherless_key = tmp_fai;
@ -11027,6 +11102,8 @@ Current version indicated by LITEVER below.
localsettings.saved_dalle_url = custom_oai_endpoint + default_oai_image_endpoint; localsettings.saved_dalle_url = custom_oai_endpoint + default_oai_image_endpoint;
localsettings.saved_oai_tts_key = custom_oai_key; localsettings.saved_oai_tts_key = custom_oai_key;
localsettings.saved_oai_tts_url = custom_oai_endpoint + default_oai_tts_endpoint; localsettings.saved_oai_tts_url = custom_oai_endpoint + default_oai_tts_endpoint;
localsettings.saved_oai_embd_key = custom_oai_key;
localsettings.saved_oai_embd_url = custom_oai_endpoint + default_oai_embeddings_endpoint;
} }
else if(epchoice==7) else if(epchoice==7)
{ {
@ -12391,6 +12468,7 @@ Current version indicated by LITEVER below.
document.getElementById("instruct_endtag_end").value = localsettings.instruct_endtag_end; document.getElementById("instruct_endtag_end").value = localsettings.instruct_endtag_end;
document.getElementById("raw_instruct_tags").checked = localsettings.raw_instruct_tags; document.getElementById("raw_instruct_tags").checked = localsettings.raw_instruct_tags;
document.getElementById("show_endpoint_selector").checked = localsettings.show_endpoint_selector; document.getElementById("show_endpoint_selector").checked = localsettings.show_endpoint_selector;
document.getElementById("never_rewind_ctx").checked = localsettings.never_rewind_ctx;
document.getElementById("render_streaming_markdown").checked = localsettings.render_streaming_markdown; document.getElementById("render_streaming_markdown").checked = localsettings.render_streaming_markdown;
document.getElementById("min_p").value = localsettings.min_p; document.getElementById("min_p").value = localsettings.min_p;
document.getElementById("dynatemp_range").value = localsettings.dynatemp_range; document.getElementById("dynatemp_range").value = localsettings.dynatemp_range;
@ -12919,6 +12997,7 @@ Current version indicated by LITEVER below.
localsettings.persist_session = (document.getElementById("persist_session").checked ? true : false); localsettings.persist_session = (document.getElementById("persist_session").checked ? true : false);
localsettings.raw_instruct_tags = (document.getElementById("raw_instruct_tags").checked ? true : false); localsettings.raw_instruct_tags = (document.getElementById("raw_instruct_tags").checked ? true : false);
localsettings.show_endpoint_selector = (document.getElementById("show_endpoint_selector").checked ? true : false); localsettings.show_endpoint_selector = (document.getElementById("show_endpoint_selector").checked ? true : false);
localsettings.never_rewind_ctx = (document.getElementById("never_rewind_ctx").checked ? true : false);
localsettings.render_streaming_markdown = (document.getElementById("render_streaming_markdown").checked ? true : false); localsettings.render_streaming_markdown = (document.getElementById("render_streaming_markdown").checked ? true : false);
if(document.getElementById("opmode").value==1) if(document.getElementById("opmode").value==1)
{ {
@ -13568,13 +13647,12 @@ Current version indicated by LITEVER below.
current_anotetemplate = document.getElementById("anotetemplate").value; current_anotetemplate = document.getElementById("anotetemplate").value;
anote_strength = document.getElementById("anote_strength").value; anote_strength = document.getElementById("anote_strength").value;
newlineaftermemory = (document.getElementById("newlineaftermemory").checked?true:false); newlineaftermemory = (document.getElementById("newlineaftermemory").checked?true:false);
documentdb_enabled = document.getElementById("documentdb_enabled").checked?true:false; documentdb_provider = document.getElementById("documentdb_provider").value;
documentdb_searchhistory = document.getElementById("documentdb_searchhistory").checked?true:false; documentdb_searchhistory = document.getElementById("documentdb_searchhistory").checked?true:false;
documentdb_numresults = document.getElementById("documentdb_numresults").value; documentdb_numresults = document.getElementById("documentdb_numresults").value;
documentdb_searchrange = document.getElementById("documentdb_searchrange").value; documentdb_searchrange = document.getElementById("documentdb_searchrange").value;
documentdb_chunksize = document.getElementById("documentdb_chunksize").value; documentdb_chunksize = document.getElementById("documentdb_chunksize").value;
documentdb_data = document.getElementById("documentdb_data").value; documentdb_data = document.getElementById("documentdb_data").value;
documentdb_useembeddings = document.getElementById("documentdb_useembeddings").checked ? true : false;
documentdb_numresults = parseInt(documentdb_numresults); documentdb_numresults = parseInt(documentdb_numresults);
documentdb_numresults = cleannum(documentdb_numresults,1,10); documentdb_numresults = cleannum(documentdb_numresults,1,10);
documentdb_searchrange = parseInt(documentdb_searchrange); documentdb_searchrange = parseInt(documentdb_searchrange);
@ -13995,13 +14073,12 @@ Current version indicated by LITEVER below.
wi_searchdepth = 0; wi_searchdepth = 0;
wi_insertlocation = 0; wi_insertlocation = 0;
current_anotetemplate = "[Author's note: <|>]"; current_anotetemplate = "[Author's note: <|>]";
documentdb_enabled = false; documentdb_provider = 0; //disabled
documentdb_searchhistory = false; documentdb_searchhistory = false;
documentdb_numresults = 3; documentdb_numresults = 3;
documentdb_searchrange = 300; documentdb_searchrange = 300;
documentdb_chunksize = 800; documentdb_chunksize = 800;
documentdb_data = ""; documentdb_data = "";
documentdb_useembeddings = false;
} }
if(localsettings.inject_randomness_seed>0) if(localsettings.inject_randomness_seed>0)
{ {
@ -15307,7 +15384,7 @@ Current version indicated by LITEVER below.
//if there is no memory, then we can be a lot of lenient with the character counts since the backend will truncate excess anyway //if there is no memory, then we can be a lot of lenient with the character counts since the backend will truncate excess anyway
chars_per_token = 4.8; chars_per_token = 4.8;
} }
if (is_using_kcpp_with_added_memory()) //easily handle overflow if (is_using_kcpp_with_added_memory() && !localsettings.never_rewind_ctx) //easily handle overflow
{ {
chars_per_token = 6; chars_per_token = 6;
} }
@ -15901,7 +15978,7 @@ Current version indicated by LITEVER below.
} }
// TextDB Long term memory minisearch // TextDB Long term memory minisearch
if (documentdb_enabled) if (documentdb_provider > 0)
{ {
// Finds the relevant memory fragments, formats them in a similar way to an authors note and inserts them before WI // Finds the relevant memory fragments, formats them in a similar way to an authors note and inserts them before WI
const ltmSearchQuery = !!rawNewText ? rawNewText : gametext_arr.length > 0 ? gametext_arr.slice(-1)[0] : undefined; const ltmSearchQuery = !!rawNewText ? rawNewText : gametext_arr.length > 0 ? gametext_arr.slice(-1)[0] : undefined;
@ -15984,7 +16061,7 @@ Current version indicated by LITEVER below.
{ {
truncated_memory = replace_placeholders(truncated_memory,false,false,true); truncated_memory = replace_placeholders(truncated_memory,false,false,true);
truncated_anote = replace_placeholders(truncated_anote,false,false,false); truncated_anote = replace_placeholders(truncated_anote,false,false,false);
if(!is_using_kcpp_with_added_memory()) if(!is_using_kcpp_with_added_memory() || localsettings.never_rewind_ctx)
{ {
let augmented_len = truncated_memory.length + truncated_context.length + truncated_anote.length; let augmented_len = truncated_memory.length + truncated_context.length + truncated_anote.length;
let excess_len = augmented_len - max_allowed_characters; //if > 0, then we exceeded context window let excess_len = augmented_len - max_allowed_characters; //if > 0, then we exceeded context window
@ -16011,7 +16088,7 @@ Current version indicated by LITEVER below.
} }
anote_insert_idx = clamp(anote_insert_idx, 0, truncated_context.length); anote_insert_idx = clamp(anote_insert_idx, 0, truncated_context.length);
truncated_context = truncated_context.slice(0, anote_insert_idx) + truncated_anote + truncated_context.slice(anote_insert_idx); truncated_context = truncated_context.slice(0, anote_insert_idx) + truncated_anote + truncated_context.slice(anote_insert_idx);
if(!is_using_kcpp_with_added_memory()) if(!is_using_kcpp_with_added_memory() || localsettings.never_rewind_ctx)
{ {
truncated_context = truncated_memory + truncated_context; truncated_context = truncated_memory + truncated_context;
} }
@ -16019,7 +16096,7 @@ Current version indicated by LITEVER below.
truncated_context = replace_placeholders(truncated_context,false,false,true); truncated_context = replace_placeholders(truncated_context,false,false,true);
if(is_using_kcpp_with_added_memory()) if(is_using_kcpp_with_added_memory() && !localsettings.never_rewind_ctx)
{ {
last_token_budget = (truncated_memory.length + truncated_context.length) + "/" + max_allowed_characters; last_token_budget = (truncated_memory.length + truncated_context.length) + "/" + max_allowed_characters;
} }
@ -16049,7 +16126,7 @@ Current version indicated by LITEVER below.
"models": selected_models.map((m) => { return m.name }), "models": selected_models.map((m) => { return m.name }),
}; };
if(is_using_kcpp_with_added_memory()) if(is_using_kcpp_with_added_memory() && !localsettings.never_rewind_ctx)
{ {
submit_payload.params.memory = truncated_memory; submit_payload.params.memory = truncated_memory;
submit_payload.params.trim_stop = true; submit_payload.params.trim_stop = true;
@ -21033,7 +21110,7 @@ Current version indicated by LITEVER below.
start_editing_wi(); start_editing_wi();
update_wi(); update_wi();
document.getElementById("documentdb_enabled").checked = documentdb_enabled; document.getElementById("documentdb_provider").value = documentdb_provider;
document.getElementById("documentdb_searchhistory").checked = documentdb_searchhistory; document.getElementById("documentdb_searchhistory").checked = documentdb_searchhistory;
document.getElementById("documentdb_numresults").value = documentdb_numresults document.getElementById("documentdb_numresults").value = documentdb_numresults
document.getElementById("documentdb_searchrange").value = documentdb_searchrange; document.getElementById("documentdb_searchrange").value = documentdb_searchrange;
@ -21042,17 +21119,32 @@ Current version indicated by LITEVER below.
document.getElementById("documentdb_searchrange_slide").value = documentdb_searchrange; document.getElementById("documentdb_searchrange_slide").value = documentdb_searchrange;
document.getElementById("documentdb_chunksize_slide").value = documentdb_chunksize; document.getElementById("documentdb_chunksize_slide").value = documentdb_chunksize;
document.getElementById("documentdb_data").value = documentdb_data; document.getElementById("documentdb_data").value = documentdb_data;
document.getElementById("documentdb_useembeddings").checked = documentdb_useembeddings; let providerdropdown = document.getElementById("documentdb_provider");
const kcppEmbeddingDropdownOption = Array.from(providerdropdown.options).find(opt => opt.value === "2");
if(is_using_kcpp_with_embeddings()) if(is_using_kcpp_with_embeddings())
{ {
document.getElementById("useembeddingslabel").classList.remove("color_red"); kcppEmbeddingDropdownOption.disabled = false;
document.getElementById("documentdb_useembeddings").disabled = false;
} }
else else
{ {
document.getElementById("useembeddingslabel").classList.add("color_red"); if(document.getElementById("documentdb_provider").value=="2")
document.getElementById("documentdb_useembeddings").disabled = true; {
document.getElementById("documentdb_useembeddings").checked = false; document.getElementById("documentdb_provider").value = 1;
}
kcppEmbeddingDropdownOption.disabled = true;
}
toggle_documentdb_provider();
}
function toggle_documentdb_provider()
{
if(document.getElementById("documentdb_provider").value=="3")
{
document.getElementById("documentdb_oai_buttons").classList.remove("hidden");
}
else
{
document.getElementById("documentdb_oai_buttons").classList.add("hidden");
} }
} }
@ -22551,21 +22643,47 @@ Current version indicated by LITEVER below.
} }
const generateNewEmbedding = asyncRunner(function* (text) { //generates new embedding from kcpp const generateNewEmbedding = asyncRunner(function* (text) { //generates new embedding from kcpp
let reqOpt = {
method: 'POST', // or 'PUT' if (documentdb_provider == 3) //openai embeddings provider
headers: get_kobold_header(), {
body: JSON.stringify({ let selmodel = document.getElementById("oai_embd_model").value;
"input": text, let reqOpt = {
"truncate": true method: 'POST',
}), headers: {
}; 'Content-Type': 'application/json',
if (globalabortcontroller) { 'Authorization': 'Bearer ' + localsettings.saved_oai_embd_key
reqOpt.signal = globalabortcontroller.signal; },
body: JSON.stringify({
"input": text,
"model": selmodel,
"encoding_format": "float"
})
};
if (globalabortcontroller) {
reqOpt.signal = globalabortcontroller.signal;
}
let sub_endpt = localsettings.saved_oai_embd_url;
return fetch(sub_endpt, reqOpt).then((response) => response.json()).catch(err=>{
console.log("error while fetching embeddings: " + err);
});
} else { //kcpp embeddings provider
let reqOpt = {
method: 'POST', // or 'PUT'
headers: get_kobold_header(),
body: JSON.stringify({
"input": text,
"truncate": true
}),
};
if (globalabortcontroller) {
reqOpt.signal = globalabortcontroller.signal;
}
let sub_endpt = apply_proxy_url(`${custom_kobold_endpoint}/api/extra/embeddings`);
return fetch(sub_endpt, reqOpt).then((response) => response.json()).catch(err=>{
console.log("error while fetching embeddings: " + err);
});
} }
let sub_endpt = apply_proxy_url(`${custom_kobold_endpoint}/api/extra/embeddings`);
return fetch(sub_endpt, reqOpt).then((response) => response.json()).catch(err=>{
console.log("error while fetching embeddings: " + err);
});
}); });
const DBComputeAndLoadEmbedding = asyncRunner(function* (hash, documentName, documentContent) //gets a cached embedding, recomputes if missing const DBComputeAndLoadEmbedding = asyncRunner(function* (hash, documentName, documentContent) //gets a cached embedding, recomputes if missing
{ {
@ -22791,7 +22909,7 @@ Current version indicated by LITEVER below.
}).filter(c => !!c.snippet); }).filter(c => !!c.snippet);
let miniSearch; let miniSearch;
if (documentdb_useembeddings && is_using_kcpp_with_embeddings()) if ((documentdb_provider==2 && is_using_kcpp_with_embeddings()) || documentdb_provider==3)
{ {
let searchResults = yield getRankedEmbeddings(searchStr, paragraphs); let searchResults = yield getRankedEmbeddings(searchStr, paragraphs);
searchResults = searchResults.filter(x=>x.similarity>minSimilarity); searchResults = searchResults.filter(x=>x.similarity>minSimilarity);
@ -23426,26 +23544,35 @@ Current version indicated by LITEVER below.
<div class="context_tab_container" id="documentdb_tab_container"> <div class="context_tab_container" id="documentdb_tab_container">
<div class="settinglabel" style="padding: 4px;">Automatically search and include relevant snippets from a text document or history.</div> <div class="settinglabel" style="padding: 4px;">Automatically search and include relevant snippets from a text document or history.</div>
<div class="settinglabel" style="padding: 4px;"> <div class="settinglabel" style="padding: 4px;">
<div class="justifyleft settingsmall" title="Enable TextDB">Enable TextDB </div> <div class="justifyleft settingsmall" title="Select TextDB Provider">Select TextDB Provider <span class="helpicon">?
<input title="Enable TextDB" type="checkbox" id="documentdb_enabled" style="margin:0px 0 0;"> <span class="helptext">Disabled does not use TextDB. Local TextDB does all searches directly in browser with strings. KoboldCpp Embeddings relies on a loaded Kcpp Embeddings model to generate embeddings. OpenAI Embeddings uses a remote OpenAI API to generate embeddings.</span></span></div>
</div> <select title="Select TextDB Provider" style="height:20px;padding:0px;margin:0px 4px 0; width:150px;font-size:12px;" class="form-control" onchange="toggle_documentdb_provider()" id="documentdb_provider">
<option value="0">Disabled</option>
<div class="settinglabel" style="padding: 4px;"> <option value="1">Local TextDB</option>
<div class="justifyleft settingsmall" id="useembeddingslabel" title="Use Embeddings for Searching">Use Embeddings for Searching <span class="helpicon">? <option value="2">KoboldCpp Embeddings</option>
<span class="helptext">If enabled, the text DB is converted to vectors using the KoboldCPP embedding endpoint. If not, it uses the traditional TextDB keyword based search. Generally, embeddings are slower to generate initially (so when making changes to DB the next response might be very slow) - but may understand the context of the sentence better while also potentially supporting multiple languages.</span></span></div> <option value="3">OpenAI Embeddings</option>
<input title="Use Embeddings for Searching" type="checkbox" id="documentdb_useembeddings" style="margin:0px 0 0;"> </select>
<div id="documentdb_oai_buttons" style="display: flex;">
<button type="button" class="btn btn-primary" style="margin:0px; padding:0px; padding-left:2px;padding-right:2px;font-size:11px;margin-right:2px;" onclick="set_oai_embd_url()">Set URL</button>
<button type="button" class="btn btn-primary" style="margin:0px; padding:0px; padding-left:2px;padding-right:2px;font-size:11px;" onclick="set_oai_embd_key()">Set Key</button>
<select title="Select OpenAI Embed Model" style="height:20px;padding:0px;margin:0px 4px 0; width:150px;font-size:12px;" class="form-control" id="oai_embd_model">
<option value="text-embedding-3-small">text-embedding-3-small</option>
<option value="text-embedding-3-large">text-embedding-3-large</option>
<option value="text-embedding-ada-002">text-embedding-ada-002</option>
</select>
</div>
</div> </div>
<div class="settinglabel" style="padding: 4px;"> <div class="settinglabel" style="padding: 4px;">
<div class="justifyleft settingsmall" title="Delete Embedding cache">Delete Embedding cache <span class="helpicon">? <div class="justifyleft settingsmall" title="Delete Embedding cache">Delete Embedding cache <span class="helpicon">?
<span class="helptext">When embeddings are enabled, they get generated by the KCPP server and then are cached in the web browser. This button clears the browser cache.</span></span></div> <span class="helptext">When embeddings are enabled, they get generated by the KCPP server and then are cached in the web browser. This button clears the browser cache.</span></span></div>
<button title="Delete Embedding cache" class="btn btn-primary" onclick="DBClearEmbeddings()" style="margin:0px 0 0;">Delete Embedding cache</button> <button title="Delete Embedding cache" class="btn btn-primary" onclick="DBClearEmbeddings()" style="font-size:12px;padding:2px 2px;margin:0px 0 0;">Delete Embedding cache</button>
</div> </div>
<div class="settinglabel" style="padding: 4px;"> <div class="settinglabel" style="padding: 4px;">
<div class="justifyleft settingsmall" title="Add document to TextDB">Add document to TextDB <span class="helpicon">? <div class="justifyleft settingsmall" title="Add document to TextDB">Add document to TextDB <span class="helpicon">?
<span class="helptext">Tries to extract the text from the document, adding (or overwriting) an existing document in the TextDB with the same name.</span></span></div> <span class="helptext">Tries to extract the text from the document, adding (or overwriting) an existing document in the TextDB with the same name.</span></span></div>
<button title="Add document to TextDB" class="btn btn-primary" onclick="addDocumentToTextDB()" style="margin:0px 0 0;">Add document to TextDB</button> <button title="Add document to TextDB" class="btn btn-primary" onclick="addDocumentToTextDB()" style="font-size:12px;padding:2px 2px;margin:0px 0 0;">Add document to TextDB</button>
</div> </div>
<div class="settinglabel" style="padding: 4px;"> <div class="settinglabel" style="padding: 4px;">
@ -24619,6 +24746,11 @@ Current version indicated by LITEVER below.
class="helptext">Allows you to change the connected custom endpoint at runtime even in local mode.</span></span></div> class="helptext">Allows you to change the connected custom endpoint at runtime even in local mode.</span></span></div>
<input title="Show Local Endpoint Selector" type="checkbox" id="show_endpoint_selector" style="margin:0px 0px 0px 0px;"> <input title="Show Local Endpoint Selector" type="checkbox" id="show_endpoint_selector" style="margin:0px 0px 0px 0px;">
</div> </div>
<div class="settinglabel">
<div class="justifyleft settingsmall">NeverRewindCtxWindow <span class="helpicon">?<span
class="helptext">Prevents ever rewinding to context that has already been shifted out of the context window. </span></span></div>
<input title="Never Rewind Context Window" type="checkbox" id="never_rewind_ctx" style="margin:0px 0px 0px 0px;">
</div>
</div> </div>
<div class="settingitem wide"> <div class="settingitem wide">

View file

@ -67,6 +67,7 @@ friendlymodelname = "inactive"
friendlysdmodelname = "inactive" friendlysdmodelname = "inactive"
friendlyembeddingsmodelname = "inactive" friendlyembeddingsmodelname = "inactive"
lastgeneratedcomfyimg = b'' lastgeneratedcomfyimg = b''
lastuploadedcomfyimg = b''
fullsdmodelpath = "" #if empty, it's not initialized fullsdmodelpath = "" #if empty, it's not initialized
mmprojpath = "" #if empty, it's not initialized mmprojpath = "" #if empty, it's not initialized
password = "" #if empty, no auth key required password = "" #if empty, no auth key required
@ -1563,11 +1564,14 @@ def sd_comfyui_tranform_params(genparams):
pos = inp.get("positive",[]) #positive prompt node pos = inp.get("positive",[]) #positive prompt node
neg = inp.get("negative",[]) #negative prompt node neg = inp.get("negative",[]) #negative prompt node
imgsize = inp.get("latent_image",[]) #image size node latentimg = inp.get("latent_image",[]) #image size node
if imgsize and isinstance(imgsize, list) and len(imgsize) > 0: if latentimg and isinstance(latentimg, list) and len(latentimg) > 0:
temp = promptobj.get(str(imgsize[0]), {}) temp = promptobj.get(str(latentimg[0]), {}) #now, this may be a VAEEncode or EmptyLatentImage
nodetype = temp.get("class_type", "") #if its a VAEEncode, it will have pixels
temp = temp.get('inputs', {}) temp = temp.get('inputs', {})
if nodetype=="VAEEncode" and lastuploadedcomfyimg!="": #img2img
genparams["init_images"] = [lastuploadedcomfyimg]
genparams["width"] = temp.get("width", 512) genparams["width"] = temp.get("width", 512)
genparams["height"] = temp.get("height", 512) genparams["height"] = temp.get("height", 512)
if neg and isinstance(neg, list) and len(neg) > 0: if neg and isinstance(neg, list) and len(neg) > 0:
@ -2481,7 +2485,7 @@ class KcppServerRequestHandler(http.server.SimpleHTTPRequestHandler):
super().log_message(format, *args) super().log_message(format, *args)
pass pass
def extract_transcribe_from_file_upload(self, body): def extract_formdata_from_file_upload(self, body):
result = {"file": None, "prompt": None, "language": None} result = {"file": None, "prompt": None, "language": None}
try: try:
if 'content-type' in self.headers and self.headers['content-type']: if 'content-type' in self.headers and self.headers['content-type']:
@ -2490,6 +2494,7 @@ class KcppServerRequestHandler(http.server.SimpleHTTPRequestHandler):
fparts = body.split(boundary) fparts = body.split(boundary)
for fpart in fparts: for fpart in fparts:
detected_upload_filename = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', fpart.decode('utf-8',errors='ignore')) detected_upload_filename = re.findall(r'Content-Disposition.*name="file"; filename="(.*)"', fpart.decode('utf-8',errors='ignore'))
detected_upload_filename_comfy = re.findall(r'Content-Disposition.*name="image"; filename="(.*)"', fpart.decode('utf-8',errors='ignore'))
if detected_upload_filename and len(detected_upload_filename)>0: if detected_upload_filename and len(detected_upload_filename)>0:
utfprint(f"Detected uploaded file: {detected_upload_filename[0]}") utfprint(f"Detected uploaded file: {detected_upload_filename[0]}")
file_content_start = fpart.find(b'\r\n\r\n') + 4 # Position after headers file_content_start = fpart.find(b'\r\n\r\n') + 4 # Position after headers
@ -2500,6 +2505,16 @@ class KcppServerRequestHandler(http.server.SimpleHTTPRequestHandler):
file_data_base64 = base64.b64encode(file_data).decode('utf-8',"ignore") file_data_base64 = base64.b64encode(file_data).decode('utf-8',"ignore")
base64_string = f"data:audio/wav;base64,{file_data_base64}" base64_string = f"data:audio/wav;base64,{file_data_base64}"
result["file"] = base64_string result["file"] = base64_string
elif detected_upload_filename_comfy and len(detected_upload_filename_comfy)>0:
utfprint(f"Detected uploaded image: {detected_upload_filename_comfy[0]}")
file_content_start = fpart.find(b'\r\n\r\n') + 4 # Position after headers
file_content_end = fpart.rfind(b'\r\n') # Ending boundary
if file_content_start != -1 and file_content_end != -1:
if "file" in result and result["file"] is None:
file_data = fpart[file_content_start:file_content_end]
file_data_base64 = base64.b64encode(file_data).decode('utf-8',"ignore")
base64_string = f"{file_data_base64}"
result["file"] = base64_string
# Check for fields # Check for fields
detected_prompt_field = re.findall(r'Content-Disposition.*name="prompt"\r\n\r\n(.*)\r\n', fpart.decode('utf-8', errors='ignore')) detected_prompt_field = re.findall(r'Content-Disposition.*name="prompt"\r\n\r\n(.*)\r\n', fpart.decode('utf-8', errors='ignore'))
@ -2926,7 +2941,7 @@ Change Mode<br>
def do_GET(self): def do_GET(self):
global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui
global last_req_time, start_time global last_req_time, start_time
global savedata_obj, has_multiplayer, multiplayer_turn_major, multiplayer_turn_minor, multiplayer_story_data_compressed, multiplayer_dataformat, multiplayer_lastactive, maxctx, maxhordelen, friendlymodelname, lastgeneratedcomfyimg, KcppVersion, totalgens, preloaded_story, exitcounter, currentusergenkey, friendlysdmodelname, fullsdmodelpath, mmprojpath, password, friendlyembeddingsmodelname global savedata_obj, has_multiplayer, multiplayer_turn_major, multiplayer_turn_minor, multiplayer_story_data_compressed, multiplayer_dataformat, multiplayer_lastactive, maxctx, maxhordelen, friendlymodelname, lastuploadedcomfyimg, lastgeneratedcomfyimg, KcppVersion, totalgens, preloaded_story, exitcounter, currentusergenkey, friendlysdmodelname, fullsdmodelpath, mmprojpath, password, friendlyembeddingsmodelname
self.path = self.path.rstrip('/') self.path = self.path.rstrip('/')
response_body = None response_body = None
content_type = 'application/json' content_type = 'application/json'
@ -3145,7 +3160,7 @@ Change Mode<br>
return return
def do_POST(self): def do_POST(self):
global modelbusy, requestsinqueue, currentusergenkey, totalgens, pendingabortkey, lastgeneratedcomfyimg, multiplayer_turn_major, multiplayer_turn_minor, multiplayer_story_data_compressed, multiplayer_dataformat, multiplayer_lastactive, net_save_slots global modelbusy, requestsinqueue, currentusergenkey, totalgens, pendingabortkey, lastuploadedcomfyimg, lastgeneratedcomfyimg, multiplayer_turn_major, multiplayer_turn_minor, multiplayer_story_data_compressed, multiplayer_dataformat, multiplayer_lastactive, net_save_slots
contlenstr = self.headers['content-length'] contlenstr = self.headers['content-length']
content_length = 0 content_length = 0
body = None body = None
@ -3602,6 +3617,12 @@ Change Mode<br>
response_body = (json.dumps({"success": result}).encode()) response_body = (json.dumps({"success": result}).encode())
else: else:
response_body = (json.dumps({"success": False}).encode()) response_body = (json.dumps({"success": False}).encode())
elif self.path.startswith('/api/upload/image') or self.path.startswith("/upload/image"): #comfyui compatible
lastuploadedcomfyimg = b''
formdata = self.extract_formdata_from_file_upload(body)
if "file" in formdata and formdata["file"]:
lastuploadedcomfyimg = formdata["file"]
response_body = (json.dumps({"name": "kcpp_img2img.jpg", "subfolder": "", "type": "input"}).encode())
elif self.path.endswith('/request'): elif self.path.endswith('/request'):
api_format = 1 api_format = 1
elif self.path.endswith(('/api/v1/generate', '/api/latest/generate')): elif self.path.endswith(('/api/v1/generate', '/api/latest/generate')):
@ -3658,7 +3679,7 @@ Change Mode<br>
except Exception: except Exception:
genparams = None genparams = None
if is_transcribe: #fallback handling of file uploads if is_transcribe: #fallback handling of file uploads
formdata = self.extract_transcribe_from_file_upload(body) formdata = self.extract_formdata_from_file_upload(body)
if "file" in formdata and formdata["file"]: if "file" in formdata and formdata["file"]:
b64wav = formdata["file"] b64wav = formdata["file"]
genparams = {"audio_data":b64wav} genparams = {"audio_data":b64wav}