├── .gitignore ├── README.md ├── out └── sample.png ├── package.json └── src ├── 01_api_basic.js ├── 02_api_getHistory.js ├── 03_api_getImage.js ├── 04_api_interrupt.js ├── 05_ws_basic.js ├── 06_ws_simple_message.js ├── 07_ws_message.js ├── 08_api_ws.js ├── 09_bonus.js ├── api ├── config.js ├── getImagePNG.js ├── interrupt.js └── postQueue.js ├── config.js ├── utils └── index.js └── workflow └── 01_workflow_api_basic.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | .pnpm-debug.log* 9 | package-lock.json 10 | 11 | # Dependency directories 12 | node_modules/ 13 | 14 | # Optional npm cache directory 15 | .npm 16 | 17 | # dotenv environment variable files 18 | .env 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | .env.local 23 | 24 | # Sandbox 25 | sandbox 26 | 27 | # yarn v2 28 | .yarn/cache 29 | .yarn/unplugged 30 | .yarn/build-state.yml 31 | .yarn/install-state.gz 32 | .pnp.* 33 | 34 | # Mac 35 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ComfyUI-API-WS 2 | Example for how to communicate with ComfyUI via API and Websocket 3 | 4 | # How to use 5 | 6 | clone this repo 7 | 8 | `git clone https://github.com/4rmx/comfyui-api-ws` 9 | 10 | and install dependency 11 | 12 | `npm install` 13 | 14 | or 15 | 16 | `yarn install` 17 | 18 | this workflow required costom_node `https://github.com/BlenderNeko/ComfyUI_ADV_CLIP_emb` 19 | 20 | start ComfyUI server 21 | 22 | You may use args `--listen` if you want to make the server listen to network connections. 23 | 24 | or use args `--port` to make the server listen on a specific port. 25 | 26 | and then change your ComfyUI server endpoint at file `/src/config` 27 | 28 | feel free to navigate the example eg. 29 | `node src/01_api_basic.js` 30 | # support me 31 | 32 | 33 | -------------------------------------------------------------------------------- /out/sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/4rmx/comfyui-api-ws/3da7a47cb29bc4199e3d01a0a72a6c2b34af7425/out/sample.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "comfyui-api-ws", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/4rmx/comfyui-api-ws.git" 12 | }, 13 | "keywords": [], 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/4rmx/comfyui-api-ws/issues" 18 | }, 19 | "homepage": "https://github.com/4rmx/comfyui-api-ws#readme", 20 | "dependencies": { 21 | "axios": "^0.27.2", 22 | "cli-progress": "^3.12.0", 23 | "uuid": "^9.0.1", 24 | "ws": "^8.14.2" 25 | } 26 | } -------------------------------------------------------------------------------- /src/01_api_basic.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const { COMFYUI_API_ENDPOINT } = require('./config'); 3 | const wf = require('./workflow/01_workflow_api_basic.json'); 4 | 5 | async function executePrompt() { 6 | try { 7 | // change positive prompt 8 | wf[3].inputs.text = '1girl'; 9 | 10 | // change file name in save image node 11 | wf[7].inputs.filename_prefix = 'sample'; 12 | 13 | // log workflow befor send 14 | console.log(wf); 15 | 16 | // send to api 17 | const response = await axios.post(`http://${COMFYUI_API_ENDPOINT}/prompt`, { prompt: wf }); 18 | 19 | /** @type {import('./api/postQueue').ResponseSuccess} */ 20 | const data = response.data; 21 | 22 | // response prompt_id 23 | console.log('prompt_id:', data.prompt_id); 24 | } catch (err) { 25 | console.log(err); 26 | } 27 | } 28 | 29 | executePrompt(); -------------------------------------------------------------------------------- /src/02_api_getHistory.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef Images 3 | * @property {string} filename 4 | * @property {string} subfolder 5 | * @property {string} type 6 | * 7 | * @typedef {Object. }>} Outputs 8 | * 9 | * @typedef {Object.} ResponseSuccess 10 | */ 11 | 12 | const { default: axios } = require('axios'); 13 | const { COMFYUI_API_ENDPOINT } = require('./config'); 14 | 15 | // replace prompt_id from 01_basic_api response 16 | const prompt_id = 'c32003af-9d4a-44c6-97a0-89b20f0e4dac'; 17 | 18 | async function getHistory() { 19 | try { 20 | const response = await axios.get(`http://${COMFYUI_API_ENDPOINT}/history/${prompt_id}`); 21 | 22 | /** @type {ResponseSuccess} */ 23 | const data = response.data; 24 | 25 | // console.log(data[prompt_id]); 26 | console.log(data[prompt_id].outputs['7'].images); 27 | } catch (err) { 28 | console.log(err); 29 | } 30 | } 31 | 32 | getHistory(); -------------------------------------------------------------------------------- /src/03_api_getImage.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const fs = require('fs'); 3 | const { COMFYUI_API_ENDPOINT } = require('./config'); 4 | 5 | // file name and subfolder from 6 | const output = { filename: 'sample_00001_.png', subfolder: '', type: 'output' }; 7 | 8 | async function getImage() { 9 | try { 10 | // parse output object to url params 11 | const params = new URLSearchParams(output).toString(); 12 | 13 | // send request with specific resposponseType specific for save .png with fs 14 | const response = await axios.get(`http://${COMFYUI_API_ENDPOINT}/view?${params}`, { responseType: 'arraybuffer' }); 15 | 16 | // save png image 17 | fs.writeFileSync(`out/${output.filename}`, response.data); 18 | } catch (err) { 19 | console.log(err); 20 | } 21 | } 22 | 23 | getImage(); -------------------------------------------------------------------------------- /src/04_api_interrupt.js: -------------------------------------------------------------------------------- 1 | const { default: axios } = require('axios'); 2 | const { COMFYUI_API_ENDPOINT } = require('./config'); 3 | 4 | // send api when you need to interrupt comfyUI execution 5 | async function interrupt() { 6 | try { 7 | const response = await axios.post(`http://${COMFYUI_API_ENDPOINT}/interrupt`); 8 | console.log(response.status); 9 | } catch (err) { 10 | console.log(err); 11 | } 12 | } 13 | 14 | interrupt(); -------------------------------------------------------------------------------- /src/05_ws_basic.js: -------------------------------------------------------------------------------- 1 | const { v4: uuidv4 } = require('uuid'); 2 | const { WebSocket } = require('ws'); 3 | const { COMFYUI_API_ENDPOINT } = require('./config'); 4 | 5 | const client_id = uuidv4(); 6 | 7 | // Create Websocket instant 8 | const ws = new WebSocket(`ws://${COMFYUI_API_ENDPOINT}/ws?clientId=${client_id}`); 9 | 10 | // log when error 11 | ws.on('error', console.error); 12 | 13 | // log when socket connected 14 | ws.on('open', () => console.log('socket is connected!')); -------------------------------------------------------------------------------- /src/06_ws_simple_message.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef MessageStatus 3 | * @property {'status'} type 4 | * @property {object} data 5 | * @property {object} data.status 6 | * @property {object} data.status.exec_info 7 | * @property {number} data.status.exec_info.queue_remaining 8 | */ 9 | const { v4: uuidv4 } = require('uuid'); 10 | const { WebSocket } = require('ws'); 11 | const { COMFYUI_API_ENDPOINT } = require('./config'); 12 | 13 | // Create ClientId 14 | const client_id = uuidv4(); 15 | 16 | // Create Websocket instant 17 | const ws = new WebSocket(`ws://${COMFYUI_API_ENDPOINT}/ws?clientId=${client_id}`); 18 | 19 | // log when error 20 | ws.on('error', console.error); 21 | 22 | // handle incomming message from websocket 23 | ws.on('message', handleComfyUIMessage); 24 | 25 | // log when socket connected 26 | ws.on('open', () => console.log('socket is connected!')); 27 | 28 | /** @param {string} msg */ 29 | async function handleComfyUIMessage(msg) { 30 | try { 31 | msg = JSON.parse(msg); 32 | if (msg?.type === 'status') { 33 | /** @type {MessageStatus} */ 34 | const { data } = msg; 35 | console.log(data.status.exec_info); 36 | } else { 37 | console.log(msg); 38 | } 39 | } catch (err) { 40 | console.log(err); 41 | } 42 | } -------------------------------------------------------------------------------- /src/07_ws_message.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {'status'|'progress'|'executing'|'executed'|'execution_start'|'execution_error'|'execution_cached'} MessageType 3 | * 4 | * @typedef MsgStatus 5 | * @property {'status'} type 6 | * @property {object} data 7 | * @property {object} data.status 8 | * @property {object} data.status.exec_info 9 | * @property {number} data.status.exec_info.queue_remaining 10 | * 11 | * @typedef MsgExeStart 12 | * @property {string} type 13 | * @property {object} data 14 | * @property {string} data.prompt_id 15 | * 16 | * @typedef MsgExeCached 17 | * @property {string} type 18 | * @property {object} data 19 | * @property {} data.nodes 20 | * @property {string} data.prompt_id 21 | * 22 | * @typedef MsgExe 23 | * @property {string} type 24 | * @property {object} data 25 | * @property {string|null} data.node 26 | * @property {string} data.prompt_id 27 | * 28 | * @typedef MsgProgress 29 | * @property {string} type 30 | * @property {object} data 31 | * @property {number} data.value 32 | * @property {number} data.max 33 | * 34 | * @typedef MsgExecuted 35 | * @property {string} type 36 | * @property {object} data 37 | * @property {string} data.node 38 | * @property {object} data.output 39 | * @property {object[]} data.output.images 40 | * @property {string} data.output.images.filename 41 | * @property {string} data.output.images.subfolder 42 | * @property {string} data.output.images.type 43 | * @property {string} data.prompt_id 44 | */ 45 | 46 | const { v4: uuidv4 } = require('uuid'); 47 | const { WebSocket } = require('ws'); 48 | const fs = require('fs'); 49 | const { COMFYUI_API_ENDPOINT } = require('./config'); 50 | const wf = require('./workflow/01_workflow_api_basic.json'); 51 | const postQueue = require('./api/postQueue'); 52 | const getImagePNG = require('./api/getImagePNG'); 53 | 54 | // Create ClientId 55 | const client_id = uuidv4(); 56 | 57 | // Create Websocket instant 58 | const ws = new WebSocket(`ws://${COMFYUI_API_ENDPOINT}/ws?clientId=${client_id}`); 59 | 60 | // log when error 61 | ws.on('error', console.error); 62 | 63 | // handle incomming message from websocket 64 | ws.on('message', handleComfyUIMessage); 65 | 66 | // when socket connected 67 | ws.on('open', () => { 68 | console.log('socket is connected!'); 69 | queuePrompt(); 70 | }); 71 | 72 | /** @param {string} msg */ 73 | function handleComfyUIMessage(msg) { 74 | msg = JSON.parse(msg); 75 | /** @type {MessageType} */ 76 | const type = msg?.type; 77 | if (type === 'status') { 78 | /** @type {MsgStatus} */ 79 | const { data } = msg; 80 | // console.log(data.status.exec_info); 81 | const { queue_remaining } = data.status.exec_info; 82 | console.log({ queue_remaining }); 83 | } else if (type === 'execution_start') { 84 | /** @type {MsgExeStart} */ 85 | const { data } = msg; 86 | console.log('prompt_id:', data.prompt_id); 87 | } else if (type === 'executing') { 88 | /** @type {MsgExe} */ 89 | const { data } = msg; 90 | // when all execution is done and queue is available 91 | if (data.node === null) { 92 | console.log('DONE!'); 93 | } else { 94 | console.log(data); 95 | } 96 | } else if (type === 'executed') { 97 | // when execution is done 98 | /** @type {MsgExecuted} */ 99 | const { data } = msg; 100 | console.log(data.output.images); 101 | handleDownloadImage(data.output.images[0]); 102 | } else { 103 | console.log(msg); 104 | } 105 | }; 106 | 107 | async function queuePrompt() { 108 | try { 109 | const res = await postQueue(wf, client_id); 110 | console.log(res.data); 111 | } catch (err) { 112 | console.log(err); 113 | } 114 | } 115 | 116 | /** 117 | * @typedef Image 118 | * @property {string} filename 119 | * @property {string} subfolder 120 | * @property {string} type 121 | * 122 | * @param {Image} image 123 | */ 124 | async function handleDownloadImage(image) { 125 | try { 126 | const params = new URLSearchParams(image); 127 | const response = await getImagePNG(params); 128 | fs.writeFileSync(`out/${image.filename}`, response.data); 129 | console.log('Downloaded!'); 130 | } catch (err) { 131 | console.log(err); 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /src/08_api_ws.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {'status'|'progress'|'executing'|'executed'|'execution_start'|'execution_error'|'execution_cached'} MessageType 3 | * 4 | * @typedef MsgStatus 5 | * @property {'status'} type 6 | * @property {object} data 7 | * @property {object} data.status 8 | * @property {object} data.status.exec_info 9 | * @property {number} data.status.exec_info.queue_remaining 10 | * 11 | * @typedef MsgExeStart 12 | * @property {string} type 13 | * @property {object} data 14 | * @property {string} data.prompt_id 15 | * 16 | * @typedef MsgExeCached 17 | * @property {string} type 18 | * @property {object} data 19 | * @property {} data.nodes 20 | * @property {string} data.prompt_id 21 | * 22 | * @typedef MsgExe 23 | * @property {string} type 24 | * @property {object} data 25 | * @property {string|null} data.node 26 | * @property {string} data.prompt_id 27 | * 28 | * @typedef MsgProgress 29 | * @property {string} type 30 | * @property {object} data 31 | * @property {number} data.value 32 | * @property {number} data.max 33 | * 34 | * @typedef MsgExecuted 35 | * @property {string} type 36 | * @property {object} data 37 | * @property {string} data.node 38 | * @property {object} data.output 39 | * @property {object[]} data.output.images 40 | * @property {string} data.output.images.filename 41 | * @property {string} data.output.images.subfolder 42 | * @property {string} data.output.images.type 43 | * @property {string} data.prompt_id 44 | */ 45 | 46 | const { v4: uuidv4 } = require('uuid'); 47 | const { WebSocket } = require('ws'); 48 | const fs = require('fs'); 49 | const { COMFYUI_API_ENDPOINT } = require('./config'); 50 | const wf = require('./workflow/01_workflow_api_basic.json'); 51 | const postQueue = require('./api/postQueue'); 52 | const getImagePNG = require('./api/getImagePNG'); 53 | 54 | // Create ClientId 55 | const client_id = uuidv4(); 56 | 57 | // Create Websocket instant 58 | const ws = new WebSocket(`ws://${COMFYUI_API_ENDPOINT}/ws?clientId=${client_id}`); 59 | 60 | // log when error 61 | ws.on('error', console.error); 62 | 63 | // handle incomming message from websocket 64 | ws.on('message', handleComfyUIMessage); 65 | 66 | // when socket connected 67 | ws.on('open', () => { 68 | console.log('socket is connected!'); 69 | // start queue prompt when socket is connected! 70 | queuePrompt(); 71 | }); 72 | 73 | /** @param {string} msg */ 74 | function handleComfyUIMessage(msg) { 75 | msg = JSON.parse(msg); 76 | /** @type {MessageType} */ 77 | const type = msg?.type; 78 | if (type === 'status') { 79 | /** @type {MsgStatus} */ 80 | const { data } = msg; 81 | // console.log(data.status.exec_info); 82 | const { queue_remaining } = data.status.exec_info; 83 | console.log({ queue_remaining }); 84 | } else if (type === 'execution_start') { 85 | /** @type {MsgExeStart} */ 86 | const { data } = msg; 87 | console.log('prompt_id:', data.prompt_id); 88 | } else if (type === 'executing') { 89 | /** @type {MsgExe} */ 90 | const { data } = msg; 91 | // when all execution is done and queue is available 92 | if (data.node === null) { 93 | console.log('DONE!'); 94 | } else { 95 | console.log(data); 96 | } 97 | } else if (type === 'executed') { 98 | // when execution is done 99 | /** @type {MsgExecuted} */ 100 | const { data } = msg; 101 | console.log(data.output.images); 102 | handleDownloadImage(data.output.images[0]); 103 | } else { 104 | console.log(msg); 105 | } 106 | }; 107 | 108 | async function queuePrompt() { 109 | try { 110 | const res = await postQueue(wf, client_id); 111 | console.log(res.data); 112 | } catch (err) { 113 | console.log(err); 114 | } 115 | } 116 | 117 | /** 118 | * @typedef Image 119 | * @property {string} filename 120 | * @property {string} subfolder 121 | * @property {string} type 122 | * 123 | * @param {Image} image 124 | */ 125 | async function handleDownloadImage(image) { 126 | try { 127 | const params = new URLSearchParams(image); 128 | const response = await getImagePNG(params); 129 | fs.writeFileSync(`out/${image.filename}`, response.data); 130 | console.log('Downloaded!'); 131 | } catch (err) { 132 | console.log(err); 133 | } 134 | } 135 | 136 | -------------------------------------------------------------------------------- /src/09_bonus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {'status'|'progress'|'executing'|'executed'|'execution_start'|'execution_error'|'execution_cached'} MessageType 3 | * 4 | * @typedef MsgStatus 5 | * @property {'status'} type 6 | * @property {object} data 7 | * @property {object} data.status 8 | * @property {object} data.status.exec_info 9 | * @property {number} data.status.exec_info.queue_remaining 10 | * 11 | * @typedef MsgExeStart 12 | * @property {string} type 13 | * @property {object} data 14 | * @property {string} data.prompt_id 15 | * 16 | * @typedef MsgExeCached 17 | * @property {string} type 18 | * @property {object} data 19 | * @property {} data.nodes 20 | * @property {string} data.prompt_id 21 | * 22 | * @typedef MsgExe 23 | * @property {string} type 24 | * @property {object} data 25 | * @property {string|null} data.node 26 | * @property {string} data.prompt_id 27 | * 28 | * @typedef MsgProgress 29 | * @property {string} type 30 | * @property {object} data 31 | * @property {number} data.value 32 | * @property {number} data.max 33 | * 34 | * @typedef MsgExecuted 35 | * @property {string} type 36 | * @property {object} data 37 | * @property {string} data.node 38 | * @property {object} data.output 39 | * @property {object[]} data.output.images 40 | * @property {string} data.output.images.filename 41 | * @property {string} data.output.images.subfolder 42 | * @property {string} data.output.images.type 43 | * @property {string} data.prompt_id 44 | */ 45 | 46 | const { v4: uuidv4 } = require('uuid'); 47 | const { WebSocket } = require('ws'); 48 | const fs = require('fs'); 49 | const cliProgress = require('cli-progress'); 50 | 51 | const { COMFYUI_API_ENDPOINT } = require('./config'); 52 | const wf = require('./workflow/01_workflow_api_basic.json'); 53 | const postQueue = require('./api/postQueue'); 54 | const getImagePNG = require('./api/getImagePNG'); 55 | const { randomSeed } = require('./utils'); 56 | 57 | // Create ClientId 58 | const client_id = uuidv4(); 59 | 60 | // Create Websocket instant 61 | const ws = new WebSocket(`ws://${COMFYUI_API_ENDPOINT}/ws?clientId=${client_id}`); 62 | 63 | // create simple progress bar 64 | const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic); 65 | 66 | // log when error 67 | ws.on('error', console.error); 68 | 69 | // handle incomming message from websocket 70 | ws.on('message', handleComfyUIMessage); 71 | 72 | // when socket connected 73 | ws.on('open', () => { 74 | console.log('socket is connected!'); 75 | // start queue prompt when socket is connected! 76 | queuePrompt(); 77 | }); 78 | 79 | /** @param {string} msg */ 80 | function handleComfyUIMessage(msg) { 81 | msg = JSON.parse(msg); 82 | /** @type {MessageType} */ 83 | const type = msg?.type; 84 | if (type === 'status') { 85 | /** @type {MsgStatus} */ 86 | const { data } = msg; 87 | // console.log(data.status.exec_info); 88 | const { queue_remaining } = data.status.exec_info; 89 | console.log({ queue_remaining }); 90 | } else if (type === 'execution_start') { 91 | /** @type {MsgExeStart} */ 92 | const { data } = msg; 93 | console.log('prompt_id:', data.prompt_id); 94 | } else if (type === 'executing') { 95 | /** @type {MsgExe} */ 96 | const { data } = msg; 97 | // when all execution is done and queue is available 98 | if (data.node === null) { 99 | console.log('DONE!'); 100 | } else { 101 | console.log(data); 102 | } 103 | } else if (type === 'executed') { 104 | // when execution is done 105 | /** @type {MsgExecuted} */ 106 | const { data } = msg; 107 | console.log(data.output.images); 108 | handleDownloadImage(data.output.images[0]); 109 | } else if (type === 'progress') { 110 | // when sampler progress use progress bar to show status 111 | /** @type {MsgProgress} */ 112 | const { data } = msg; 113 | if (bar1.getProgress() === 0) { 114 | bar1.start(data.max, data.value); 115 | } else if (data.max === data.value) { 116 | bar1.update(data.value); 117 | bar1.stop(); 118 | } else { 119 | bar1.update(data.value); 120 | } 121 | } else { 122 | console.log(msg); 123 | } 124 | }; 125 | 126 | async function queuePrompt() { 127 | try { 128 | // manual random seed by js code; 129 | wf[2].inputs.seed = randomSeed(); 130 | const res = await postQueue(wf, client_id); 131 | console.log(res.data); 132 | } catch (err) { 133 | console.log(err); 134 | } 135 | } 136 | 137 | /** 138 | * @typedef Image 139 | * @property {string} filename 140 | * @property {string} subfolder 141 | * @property {string} type 142 | * 143 | * @param {Image} image 144 | */ 145 | async function handleDownloadImage(image) { 146 | try { 147 | const params = new URLSearchParams(image); 148 | const response = await getImagePNG(params); 149 | fs.writeFileSync(`out/${image.filename}`, response.data); 150 | console.log('Downloaded!'); 151 | } catch (err) { 152 | console.log(err); 153 | } 154 | } 155 | 156 | -------------------------------------------------------------------------------- /src/api/config.js: -------------------------------------------------------------------------------- 1 | const { default: baseAxios } = require('axios'); 2 | const { COMFYUI_API_ENDPOINT } = require('../config'); 3 | 4 | const comfyAPI = baseAxios.create({ baseURL: 'http://' + COMFYUI_API_ENDPOINT }); 5 | 6 | module.exports = { comfyAPI }; -------------------------------------------------------------------------------- /src/api/getImagePNG.js: -------------------------------------------------------------------------------- 1 | const { comfyAPI } = require('./config'); 2 | 3 | /** @param {string} params */ 4 | module.exports = (params) => comfyAPI.get(`view?${params}`, { responseType: 'arraybuffer' }); 5 | -------------------------------------------------------------------------------- /src/api/interrupt.js: -------------------------------------------------------------------------------- 1 | const { comfyAPI } = require('./config'); 2 | 3 | async function execute() { 4 | return comfyAPI.post('/interrupt') 5 | .then(res => { 6 | console.log(res.statusText); 7 | return res; 8 | }) 9 | .catch(err => { 10 | console.log(err); 11 | }); 12 | } 13 | 14 | execute(); -------------------------------------------------------------------------------- /src/api/postQueue.js: -------------------------------------------------------------------------------- 1 | const { comfyAPI } = require('./config'); 2 | 3 | /** 4 | * @typedef ResponseSuccess 5 | * @property {string} prompt_id 6 | * @property {number} number 7 | * @property {object} node_errors 8 | */ 9 | 10 | /** 11 | * @param {Object.} prompt 12 | * @param {string} client_id 13 | * @return {Promise>} 14 | */ 15 | module.exports = (prompt, client_id) => comfyAPI.post('prompt', { prompt, client_id }); 16 | -------------------------------------------------------------------------------- /src/config.js: -------------------------------------------------------------------------------- 1 | // configure your comfyui endpoint url here 2 | // for default local comfyui should be like 127.0.0.1:8188 or 192.168.0.1:8188 3 | module.exports = { 4 | COMFYUI_API_ENDPOINT: 'comfy.win:8188' 5 | }; -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | function countDecimals(value) { 2 | if (Math.floor(value) === value) return 0; 3 | return value.toString().split(".")[1].length || 0; 4 | } 5 | 6 | function addZero(count) { 7 | let txt = '1'; 8 | for (let i = 0; i < count; i++) { 9 | txt += '0'; 10 | } 11 | return Number(txt); 12 | } 13 | 14 | function randomSeed() { 15 | const rand = Math.random(); 16 | const count = countDecimals(rand); 17 | return Math.floor(rand * addZero(count)); 18 | } 19 | 20 | module.exports = { randomSeed }; -------------------------------------------------------------------------------- /src/workflow/01_workflow_api_basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "inputs": { 4 | "ckpt_name": "epicphotogasm_x.safetensors" 5 | }, 6 | "class_type": "CheckpointLoaderSimple" 7 | }, 8 | "2": { 9 | "inputs": { 10 | "seed": 408337996593045, 11 | "steps": 20, 12 | "cfg": 7, 13 | "sampler_name": "dpmpp_2m_sde", 14 | "scheduler": "karras", 15 | "denoise": 1, 16 | "model": [ 17 | "1", 18 | 0 19 | ], 20 | "positive": [ 21 | "3", 22 | 0 23 | ], 24 | "negative": [ 25 | "4", 26 | 0 27 | ], 28 | "latent_image": [ 29 | "5", 30 | 0 31 | ] 32 | }, 33 | "class_type": "KSampler" 34 | }, 35 | "3": { 36 | "inputs": { 37 | "text": "a cup of coffee, hot, (steam:0.1)", 38 | "clip": [ 39 | "1", 40 | 1 41 | ] 42 | }, 43 | "class_type": "CLIPTextEncode" 44 | }, 45 | "4": { 46 | "inputs": { 47 | "text": "(worst quality, low quality, normal quality:1.25), lowres, jpeg artifacts, watermark, paintings, sketches, cartoons, illustration, 3d,", 48 | "clip": [ 49 | "1", 50 | 1 51 | ] 52 | }, 53 | "class_type": "CLIPTextEncode" 54 | }, 55 | "5": { 56 | "inputs": { 57 | "width": 512, 58 | "height": 768, 59 | "batch_size": 1 60 | }, 61 | "class_type": "EmptyLatentImage" 62 | }, 63 | "6": { 64 | "inputs": { 65 | "samples": [ 66 | "2", 67 | 0 68 | ], 69 | "vae": [ 70 | "1", 71 | 2 72 | ] 73 | }, 74 | "class_type": "VAEDecode" 75 | }, 76 | "7": { 77 | "inputs": { 78 | "filename_prefix": "coffee", 79 | "images": [ 80 | "6", 81 | 0 82 | ] 83 | }, 84 | "class_type": "SaveImage" 85 | } 86 | } --------------------------------------------------------------------------------