diff --git a/index.html b/index.html index 48249ec..e4af031 100644 --- a/index.html +++ b/index.html @@ -4244,6 +4244,11 @@ const a1111_img2img_endpoint = "/sdapi/v1/img2img"; const a1111_interrogate_endpoint = "/sdapi/v1/interrogate"; + const comfy_models_endpoint = "/models/checkpoints"; + const comfy_generate_endpoint = "/prompt"; + const comfy_history_endpoint = "/history"; + const comfy_results_endpoint = "/view?filename="; + const xtts_gen_endpoint = "/tts_to_audio/"; const xtts_voices_endpoint = "/speakers_list"; const alltalk_gen_endpoint = "/api/tts-generate"; @@ -4262,6 +4267,7 @@ const default_a1111_base = "http://localhost:7860"; const default_xtts_base = " http://localhost:8020"; const default_alltalk_base = "http://localhost:7851"; + const default_comfy_base = "http://localhost:8188"; const XTTS_ID = 1000; const ALLTALK_ID = 1001; @@ -4385,10 +4391,11 @@ saved_oai_custommodel: "", //customized oai custom model saved_oai_role: 0, //0=user,1=assistant,2=system saved_a1111_url: default_a1111_base, + saved_comfy_url: default_comfy_base, saved_xtts_url: default_xtts_base, saved_alltalk_url: default_alltalk_base, prev_custom_endpoint_type: 0, //show a reconnect box to custom endpoint if needed. 0 is horde, otherwise its dropdown value+1 - generate_images_mode: (localflag?0:1), //0=off, 1=horde, 2=a1111, 3=dalle + generate_images_mode: (localflag?0:1), //0=off, 1=horde, 2=a1111, 3=dalle, 4=comfy autoscroll: true, //automatically scroll to bottom on render printer_view: false, //automatically scroll to bottom on render @@ -5144,7 +5151,10 @@ { connect_to_a1111(true); } - + else if(localsettings.generate_images_mode==4) + { + connect_to_comfyui(true); + } if(!initial_fetched_kudos && localsettings.my_api_key!=defaultsettings.my_api_key) { document.getElementById("apikey").value = localsettings.my_api_key; @@ -5290,6 +5300,137 @@ }); } + var comfyui_is_connected = false; + function connect_to_comfyui(silent=false) + { + console.log("Attempt ComfyUI Connection..."); + //establish initial connection to a1111 api + fetch(localsettings.saved_comfy_url + comfy_models_endpoint) + .then(x => x.json()) + .then(modelsdata => { + + if (modelsdata == null || modelsdata.length == 0) { + msgbox("Invalid data received or no models found. Is ComfyUI running at the url " + localsettings.saved_comfy_url + " ?\n\nIt must be launched with the flag --enable-cors-header '*' to enable API access"); + } else { + let current_loaded_model = modelsdata[0]; + //repopulate our model list + let dropdown = document.getElementById("generate_images_comfy_model"); + let selectionhtml = ``; + for (var i = 0; i < modelsdata.length; ++i) { + selectionhtml += ``; + } + dropdown.innerHTML = selectionhtml; + comfyui_is_connected = true; + } + }).catch((error) => { + if(!silent) + { + msgbox("ComfyUI Connect Error: " + error+"\nPlease make sure ComfyUI is running at "+localsettings.saved_comfy_url+" and properly configured!\n\nIt must be launched with the flag --enable-cors-header '*' to enable API access\n"); + } + comfyui_is_connected = false; + }); + } + + function generate_comfy_image(req_payload) + { + let splits = req_payload.prompt.split("###"); + let prompt = splits[0].trim(); + let negprompt = (splits.length > 1 ? splits[1] : ""); + + let genimg_payload = { + "prompt": { + "3": { + "class_type": "KSampler", + "inputs": { + "cfg": req_payload.params.cfg_scale, + "denoise": 1, + "latent_image": ["5", 0], + "model": ["4", 0], + "negative": ["7", 0], + "positive": ["6", 0], + "sampler_name": "euler", + "scheduler": "normal", + "seed": Math.floor(Math.random() * 99999999), + "steps": req_payload.params.steps + } + }, + "4": { + "class_type": "CheckpointLoaderSimple", + "inputs": { + "ckpt_name": req_payload.models[0] + } + }, + "5": { + "class_type": "EmptyLatentImage", + "inputs": { + "batch_size": 1, + "height": req_payload.params.height, + "width": req_payload.params.width + } + }, + "6": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": ["4", 1], + "text": prompt + } + }, + "7": { + "class_type": "CLIPTextEncode", + "inputs": { + "clip": ["4", 1], + "text": negprompt + } + }, + "8": { + "class_type": "VAEDecode", + "inputs": { + "samples": ["3", 0], + "vae": ["4", 2] + } + }, + "9": { + "class_type": "SaveImage", + "inputs": { + "filename_prefix": "kliteimg", + "images": ["8", 0] + } + } + } + }; + + let gen_endpoint = localsettings.saved_comfy_url + comfy_generate_endpoint; + console.log(genimg_payload); + + fetch(gen_endpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(genimg_payload), + }) + .then(x => x.json()) + .then(resp => { + console.log(resp); + if(resp.prompt_id) + { + let imgid = resp.prompt_id.toString(); + let nimgtag = "[<|p|" + imgid + "|p|>]"; + gametext_arr.push(nimgtag); + image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:prompt, poll_category:2 }; + image_db[imgid].aspect = (req_payload.params.width>req_payload.params.height?2:(req_payload.params.width { + console.log("Generation Error: " + error); + msgbox("Image Generation Failed!\n\nPlease make sure ComfyUI is running and properly configured!\n\nIt must be launched with the flag --enable-cors-header '*' to enable API access\n"); + }); + } + function generate_a1111_image(req_payload, onImagesDone) { //split the prompt @@ -5397,6 +5538,26 @@ },false); } + function set_comfy_endpoint() + { + inputBox("Enter ComfyUI API endpoint","ComfyUI Endpoint Selection",localsettings.saved_comfy_url,"Input ComfyUI API URL", ()=>{ + let userinput = getInputBoxValue(); + userinput = userinput.trim(); + if(userinput!="" && userinput.slice(-1)=="/") + { + userinput = userinput.slice(0, -1); + } + if(userinput=="") + { + userinput = default_comfy_base; + } + if (userinput != null && userinput!="") { + localsettings.saved_comfy_url = userinput.trim(); + connect_to_comfyui(false); + } + },false); + } + function set_horde_key() { inputBox("Enter AI Horde API Key.\n\nThe same key is used for image and text generation in AI Horde.","AI Horde API Key",localsettings.my_api_key,"Input AI Horde API Key", ()=>{ @@ -6500,6 +6661,7 @@ let tmp_kai = localsettings.saved_kai_addr; let tmp_kai2 = localsettings.saved_kai_key; let tmp_a1111 = localsettings.saved_a1111_url; + let tmp_comfy = localsettings.saved_comfy_url; let tmp_xtts = localsettings.saved_xtts_url; let tmp_imggen = localsettings.generate_images_mode; @@ -6539,6 +6701,7 @@ localsettings.saved_kai_addr = tmp_kai; localsettings.saved_kai_key = tmp_kai2; localsettings.saved_a1111_url = tmp_a1111; + localsettings.saved_comfy_url = tmp_comfy; localsettings.saved_xtts_url = tmp_xtts; localsettings.generate_images_mode = tmp_imggen; @@ -10541,15 +10704,12 @@ function toggle_generate_images_mode(silent=false) { - if(document.getElementById("generate_images_mode").value==0) - { - document.getElementById("generate_images_model_container").classList.add("hidden"); - document.getElementById("generate_images_dalle_container").classList.add("hidden"); - document.getElementById("generate_images_local_model_container").classList.add("hidden"); - }else if(document.getElementById("generate_images_mode").value==1){ + document.getElementById("generate_images_model_container").classList.add("hidden"); + document.getElementById("generate_images_dalle_container").classList.add("hidden"); + document.getElementById("generate_images_local_model_container").classList.add("hidden"); + document.getElementById("generate_images_comfy_container").classList.add("hidden"); + if(document.getElementById("generate_images_mode").value==1){ document.getElementById("generate_images_model_container").classList.remove("hidden"); - document.getElementById("generate_images_dalle_container").classList.add("hidden"); - document.getElementById("generate_images_local_model_container").classList.add("hidden"); if(!image_models_fetched) { //doing it this way will be more buggy, @@ -10559,14 +10719,13 @@ }); } }else if(document.getElementById("generate_images_mode").value==2){ - document.getElementById("generate_images_model_container").classList.add("hidden"); - document.getElementById("generate_images_dalle_container").classList.add("hidden"); document.getElementById("generate_images_local_model_container").classList.remove("hidden"); connect_to_a1111(silent); }else if(document.getElementById("generate_images_mode").value==3){ - document.getElementById("generate_images_model_container").classList.add("hidden"); document.getElementById("generate_images_dalle_container").classList.remove("hidden"); - document.getElementById("generate_images_local_model_container").classList.add("hidden"); + }else if(document.getElementById("generate_images_mode").value==4){ + document.getElementById("generate_images_comfy_container").classList.remove("hidden"); + connect_to_comfyui(silent); } } @@ -11410,7 +11569,7 @@ let imgid = "selfuploadimg"+(Math.floor(10000 + Math.random() * 90000)).toString(); let nimgtag = "[<|p|" + imgid + "|p|>]"; gametext_arr.push(nimgtag); - image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:"", local:true }; + image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:"", poll_category:0 }; image_db[imgid].aspect = 0; image_db[imgid].imsource = 1; //0=generated,1=uploaded let imgres = localsettings.img_allowhd?HD_RES_PX:NO_HD_RES_PX; @@ -13438,7 +13597,7 @@ //for now, append the new image directly into the gtarr let nimgtag = "[<|p|" + data.id + "|p|>]"; gametext_arr.push(nimgtag); - image_db[data.id] = { done: false, queue: "Starting", result: "", prompt:sentence, local:false }; + image_db[data.id] = { done: false, queue: "Starting", result: "", prompt:sentence, poll_category:1 }; image_db[data.id].aspect = (iwidth>iheight?2:(iwidth]"; gametext_arr.push(nimgtag); - image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:sentence, local:true }; + image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:sentence, poll_category:0 }; image_db[imgid].aspect = (iwidth>iheight?2:(iwidth{ @@ -13490,7 +13649,7 @@ let imgid = "DALLEimg"+(Math.floor(10000 + Math.random() * 90000)).toString(); let nimgtag = "[<|p|" + imgid + "|p|>]"; gametext_arr.push(nimgtag); - image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:sentence, local:true }; + image_db[imgid] = { done: false, queue: "Generating", result: "", prompt:sentence, poll_category:0 }; image_db[imgid].aspect = 0; image_db[imgid].imsource = 0; //0=generated,1=uploaded generate_dalle_image(genimg_payload,(outputimg)=>{ @@ -13510,6 +13669,12 @@ }); } } + else if(localsettings.generate_images_mode==4) //comfyui + { + let desired_model = document.getElementById("generate_images_comfy_model").value; + genimg_payload.models = [desired_model]; + generate_comfy_image(genimg_payload); + } } function interrogate_new_image(base64img, imghash, use_horde=true) @@ -13574,7 +13739,7 @@ .then((data) => { console.log('interrogate img result:', data); if (data.id && data.id != "") { - interrogation_db[data.id] = { done: false, result: "", imghash:imghash, local:false }; + interrogation_db[data.id] = { done: false, result: "", imghash:imghash, poll_category:1 }; console.log("New interrogate queued: " + data.id); } else { @@ -14083,7 +14248,7 @@ console.log("polling for pending interrogations " + imagecount); for (let key in interrogation_db) { let img = interrogation_db[key]; - if (img.done == false && !img.local) { + if (img.done == false && img.poll_category==1) { //call check fetch(stablehorde_output_interrogate_endpoint + "/" + key) .then(x => x.json()) @@ -14136,7 +14301,7 @@ console.log("polling for pending images " + imagecount); for (let key in image_db) { let img = image_db[key]; - if (img.done == false && !img.local) { + if (img.done == false && img.poll_category==1) { //call check fetch(stablehorde_poll_endpoint + "/" + key) .then(x => x.json()) @@ -14186,6 +14351,52 @@ delete image_db[key]; }); } + else if (img.done == false && img.poll_category==2) + { + //comfyui polling + fetch(localsettings.saved_comfy_url + comfy_history_endpoint + "/" + key, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + } + }) + .then(x => x.json()) + .then(resp2 => { + console.log(resp2); + if(resp2 && resp2[key] && resp2[key].status && resp2[key].status.completed) + { + img.done = true; + let finalfilename = resp2[key].outputs["9"].images[0].filename; + //fetch final image + fetch(localsettings.saved_comfy_url + comfy_results_endpoint + finalfilename) + .then((response) => { + return response.blob(); // Convert the response into a Blob + }) + .then((finalimg) => { + console.log('finalimg recv for ' + key); + const reader = new FileReader(); + reader.onloadend = () => { + img.queue = 0; + let origImg = reader.result; + let imgres = localsettings.img_allowhd?HD_RES_PX:NO_HD_RES_PX; + compressImage(origImg, (newDataUri) => { + img.result = newDataUri; + }, true, false, imgres,0.35,false); + }; + reader.readAsDataURL(finalimg); + }) + .catch((error) => { + console.error('Error:', error); + msgbox("Image poll error: " + error); + delete image_db[key]; + }); + } + }).catch((error) => { + console.log("Generation Error: " + error); + delete image_db[key]; + msgbox("Image Generation Failed!\n\nPlease make sure ComfyUI is running and properly configured!\n\nIt must be launched with the flag --enable-cors-header '*' to enable API access\n"); + }); + } } //now we loop through the image cache and swap completed images into the gametext @@ -18869,6 +19080,7 @@ + +