From 9dd1e5942163f6fc93886ec810c423d4a8504a7c Mon Sep 17 00:00:00 2001 From: LenAnderson Date: Sun, 19 Nov 2023 18:29:41 +0000 Subject: [PATCH] move requests to comfy into ST server --- .../extensions/stable-diffusion/index.js | 98 +++++++-------- .../extensions/stable-diffusion/settings.html | 2 +- src/stable-diffusion.js | 116 ++++++++++++++++++ 3 files changed, 159 insertions(+), 57 deletions(-) diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index 2732be611..bfb9eec55 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -879,7 +879,14 @@ async function validateComfyUrl() { throw new Error('URL is not set.'); } - const result = await fetch(`${extension_settings.sd.comfy_url}/system_stats`); + + const result = await fetch(`/api/sd/comfy/ping`, { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + url: extension_settings.sd.comfy_url, + }) + }); if (!result.ok) { throw new Error('ComfyUI returned an error.'); } @@ -1146,12 +1153,18 @@ async function loadComfySamplers() { } try { - const result = await fetch(`${extension_settings.sd.comfy_url}/object_info`); + + const result = await fetch(`/api/sd/comfy/samplers`, { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + url: extension_settings.sd.comfy_url, + }) + }); if (!result.ok) { throw new Error('ComfyUI returned an error.'); } - const data = await result.json(); - return data.KSampler.input.required.sampler_name[0]; + return await result.json(); } catch (error) { return []; } @@ -1366,12 +1379,17 @@ async function loadComfyModels() { } try { - const result = await fetch(`${extension_settings.sd.comfy_url}/object_info`); + const result = await fetch(`/api/sd/comfy/models`, { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + url: extension_settings.sd.comfy_url, + }) + }); if (!result.ok) { throw new Error('ComfyUI returned an error.'); } - const data = await result.json(); - return data.CheckpointLoaderSimple.input.required.ckpt_name[0].map(it=>({value:it,text:it})); + return await result.json(); } catch (error) { return []; } @@ -1420,12 +1438,17 @@ async function loadComfySchedulers() { } try { - const result = await fetch(`${extension_settings.sd.comfy_url}/object_info`); + const result = await fetch(`/api/sd/comfy/schedulers`, { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + url: extension_settings.sd.comfy_url, + }) + }); if (!result.ok) { throw new Error('ComfyUI returned an error.'); } - const data = await result.json(); - return data.KSampler.input.required.scheduler[0]; + return await result.json(); } catch (error) { return []; } @@ -1950,54 +1973,17 @@ async function generateComfyImage(prompt) { console.log(`{ "prompt": ${workflow} }`); - const promptResult = await fetch(`${extension_settings.sd.comfy_url}/prompt`, { + const promptResult = await fetch(`/api/sd/comfy/generate`, { method: 'POST', - body: `{ - "prompt": ${workflow} - }` + headers: getRequestHeaders(), + body: JSON.stringify({ + url: extension_settings.sd.comfy_url, + prompt: `{ + "prompt": ${workflow} + }`, + }) }); - if (promptResult.ok) { - const id = (await promptResult.json()).prompt_id; - let item; - while (true) { - const result = await fetch(`${extension_settings.sd.comfy_url}/history`); - if (result.ok) { - const history = await result.json(); - item = history[id]; - if (item) { - break; - } - await new Promise(resolve=>window.setTimeout(resolve, 100)); - } else { - const text = await result.text(); - throw new Error(text); - } - } - const imgInfo = Object.keys(item.outputs).map(it=>item.outputs[it].images).flat()[0]; - let img; - await new Promise(resolve=>{ - img = new Image(); - img.crossOrigin = 'anonymous'; - img.addEventListener('load', resolve); - img.addEventListener('error', (...v)=>{ - throw new Error('failed to load image'); - }); - img.src = `${extension_settings.sd.comfy_url}/view?filename=${imgInfo.filename}&subfolder=${imgInfo.subfolder}&type=${imgInfo.type}`; - }); - const canvas = new OffscreenCanvas(extension_settings.sd.width, extension_settings.sd.height); - const con = canvas.getContext('2d'); - con.drawImage(img, 0,0); - const imgBlob = await canvas.convertToBlob(); - const dataUrl = await new Promise(resolve=>{ - const reader = new FileReader(); - reader.addEventListener('load', ()=>resolve(reader.result)); - reader.readAsDataURL(imgBlob); - }); - return {format:'png', data:dataUrl.split(',').pop()}; - } else { - const text = await promptResult.text(); - throw new Error(text); - } + return {format:'png', data:await promptResult.text()}; } async function onComfyOpenWorkflowEditorClick() { diff --git a/public/scripts/extensions/stable-diffusion/settings.html b/public/scripts/extensions/stable-diffusion/settings.html index bf41d5f27..5e75caf9b 100644 --- a/public/scripts/extensions/stable-diffusion/settings.html +++ b/public/scripts/extensions/stable-diffusion/settings.html @@ -128,7 +128,7 @@ Open Workflow Editor -

Important: run ComfyUI with the --enable-cors-header http://127.0.0.1:8000 argument (adjust URL according to your SillyTavern setup)! The server must be accessible from the SillyTavern host machine.

+

Important: The server must be accessible from the SillyTavern host machine.

diff --git a/src/stable-diffusion.js b/src/stable-diffusion.js index 6443f51d1..303bbaf7e 100644 --- a/src/stable-diffusion.js +++ b/src/stable-diffusion.js @@ -347,6 +347,122 @@ function registerEndpoints(app, jsonParser) { return response.send({ prompt: originalPrompt }); } }); + + + app.post('/api/sd/comfy/ping', jsonParser, async(request, response)=>{ + try { + const url = new URL(request.body.url); + url.pathname = '/system_stats' + + const result = await fetch(url); + if (!result.ok) { + throw new Error('ComfyUI returned an error.'); + } + + return response.sendStatus(200); + } catch (error) { + console.log(error); + return response.sendStatus(500); + } + }); + + app.post('/api/sd/comfy/samplers', jsonParser, async(request, response)=>{ + try { + const url = new URL(request.body.url); + url.pathname = '/object_info' + + const result = await fetch(url); + if (!result.ok) { + throw new Error('ComfyUI returned an error.'); + } + + const data = await result.json(); + return response.send(data.KSampler.input.required.sampler_name[0]); + } catch (error) { + console.log(error); + return response.sendStatus(500); + } + }); + + app.post('/api/sd/comfy/models', jsonParser, async(request, response)=>{ + try { + const url = new URL(request.body.url); + url.pathname = '/object_info' + + const result = await fetch(url); + if (!result.ok) { + throw new Error('ComfyUI returned an error.'); + } + const data = await result.json(); + return response.send(data.CheckpointLoaderSimple.input.required.ckpt_name[0].map(it=>({value:it,text:it}))); + } catch (error) { + console.log(error); + return response.sendStatus(500); + } + }); + + app.post('/api/sd/comfy/schedulers', jsonParser, async(request, response)=>{ + try { + const url = new URL(request.body.url); + url.pathname = '/object_info' + + const result = await fetch(url); + if (!result.ok) { + throw new Error('ComfyUI returned an error.'); + } + + const data = await result.json(); + return response.send(data.KSampler.input.required.scheduler[0]); + } catch (error) { + console.log(error); + return response.sendStatus(500); + } + }); + + app.post('/api/sd/comfy/generate', jsonParser, async(request, response)=>{ + try { + const url = new URL(request.body.url); + url.pathname = '/prompt' + + const promptResult = await fetch(url, { + method: 'POST', + body: request.body.prompt, + }); + if (!promptResult.ok) { + throw new Error('ComfyUI returned an error.'); + } + + const data = await promptResult.json(); + const id = data.prompt_id; + let item; + const historyUrl = new URL(request.body.url); + historyUrl.pathname = '/history'; + while (true) { + const result = await fetch(historyUrl); + if (!result.ok) { + throw new Error('ComfyUI returned an error.'); + } + const history = await result.json(); + item = history[id]; + if (item) { + break; + } + await delay(100); + } + const imgInfo = Object.keys(item.outputs).map(it=>item.outputs[it].images).flat()[0]; + const imgUrl = new URL(request.body.url); + imgUrl.pathname = '/view'; + imgUrl.search = `?filename=${imgInfo.filename}&subfolder=${imgInfo.subfolder}&type=${imgInfo.type}`; + const imgResponse = await fetch(imgUrl); + if (!imgResponse.ok) { + throw new Error('ComfyUI returned an error.'); + } + const imgBuffer = await imgResponse.buffer(); + return response.send(imgBuffer.toString('base64')); + } catch (error) { + return response.sendStatus(500); + } + }); } module.exports = {