mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	move requests to comfy into ST server
This commit is contained in:
		| @@ -879,7 +879,14 @@ async function validateComfyUrl() { | |||||||
|             throw new Error('URL is not set.'); |             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) { |         if (!result.ok) { | ||||||
|             throw new Error('ComfyUI returned an error.'); |             throw new Error('ComfyUI returned an error.'); | ||||||
|         } |         } | ||||||
| @@ -1146,12 +1153,18 @@ async function loadComfySamplers() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     try { |     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) { |         if (!result.ok) { | ||||||
|             throw new Error('ComfyUI returned an error.'); |             throw new Error('ComfyUI returned an error.'); | ||||||
|         } |         } | ||||||
|         const data = await result.json(); |         return await result.json(); | ||||||
|         return data.KSampler.input.required.sampler_name[0]; |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         return []; |         return []; | ||||||
|     } |     } | ||||||
| @@ -1366,12 +1379,17 @@ async function loadComfyModels() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     try { |     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) { |         if (!result.ok) { | ||||||
|             throw new Error('ComfyUI returned an error.'); |             throw new Error('ComfyUI returned an error.'); | ||||||
|         } |         } | ||||||
|         const data = await result.json(); |         return await result.json(); | ||||||
|         return data.CheckpointLoaderSimple.input.required.ckpt_name[0].map(it=>({value:it,text:it})); |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         return []; |         return []; | ||||||
|     } |     } | ||||||
| @@ -1420,12 +1438,17 @@ async function loadComfySchedulers() { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     try { |     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) { |         if (!result.ok) { | ||||||
|             throw new Error('ComfyUI returned an error.'); |             throw new Error('ComfyUI returned an error.'); | ||||||
|         } |         } | ||||||
|         const data = await result.json(); |         return await result.json(); | ||||||
|         return data.KSampler.input.required.scheduler[0]; |  | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|         return []; |         return []; | ||||||
|     } |     } | ||||||
| @@ -1950,54 +1973,17 @@ async function generateComfyImage(prompt) { | |||||||
|     console.log(`{ |     console.log(`{ | ||||||
|         "prompt": ${workflow} |         "prompt": ${workflow} | ||||||
|     }`); |     }`); | ||||||
|     const promptResult = await fetch(`${extension_settings.sd.comfy_url}/prompt`, { |     const promptResult = await fetch(`/api/sd/comfy/generate`, { | ||||||
|         method: 'POST', |         method: 'POST', | ||||||
|         body: `{ |         headers: getRequestHeaders(), | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |             url: extension_settings.sd.comfy_url, | ||||||
|  |             prompt: `{ | ||||||
|                 "prompt": ${workflow} |                 "prompt": ${workflow} | ||||||
|         }` |             }`, | ||||||
|  |         }) | ||||||
|     }); |     }); | ||||||
|     if (promptResult.ok) { |     return {format:'png', data:await promptResult.text()}; | ||||||
|         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); |  | ||||||
|     } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| async function onComfyOpenWorkflowEditorClick() { | async function onComfyOpenWorkflowEditorClick() { | ||||||
|   | |||||||
| @@ -128,7 +128,7 @@ | |||||||
|                     <i class="fa-solid fa-pen-to-square"></i> |                     <i class="fa-solid fa-pen-to-square"></i> | ||||||
|                     <span>Open Workflow Editor</span> |                     <span>Open Workflow Editor</span> | ||||||
|                 </div> |                 </div> | ||||||
|                 <p><i><b>Important:</b> run ComfyUI with the <code>--enable-cors-header http://127.0.0.1:8000</code> argument (adjust URL according to your SillyTavern setup)! The server must be accessible from the SillyTavern host machine.</i></p> |                 <p><i><b>Important:</b> The server must be accessible from the SillyTavern host machine.</i></p> | ||||||
|             </div> |             </div> | ||||||
|             <label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label> |             <label for="sd_scale">CFG Scale (<span id="sd_scale_value"></span>)</label> | ||||||
|             <input id="sd_scale" type="range" min="{{scale_min}}" max="{{scale_max}}" step="{{scale_step}}" value="{{scale}}" /> |             <input id="sd_scale" type="range" min="{{scale_min}}" max="{{scale_max}}" step="{{scale_step}}" value="{{scale}}" /> | ||||||
|   | |||||||
| @@ -347,6 +347,122 @@ function registerEndpoints(app, jsonParser) { | |||||||
|             return response.send({ prompt: originalPrompt }); |             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 = { | module.exports = { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user