diff --git a/.gitignore b/.gitignore index a43654a..cea31fe 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ __pycache__/ https/ nodes/config.json workflow/my_workflow.json -workflow/my_workflow_app.json \ No newline at end of file +workflow/my_workflow_app.json +app/* \ No newline at end of file diff --git a/README.md b/README.md index 681722f..213bfd9 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,25 @@ ## -v0.6.0 🚀🚗🚚🏃‍ Workflow-to-APP +v0.7.0 🚀🚗🚚🏃‍ Workflow-to-APP +- 支持多个web app 切换 - 新增AppInfo节点,可以通过简单的配置,把workflow转变为一个Web APP。 +- Support multiple web app switching. - Add the AppInfo node, which allows you to transform the workflow into a web app by simple configuration. +![](./assets/0-m-app.png) + ![](./assets/appinfo-readme.png) + Example: - workflow ![APP info](./workflow/appinfo-workflow.svg) +[text-to-image](./workflow/Text-to-Image-app.json) APP-JSON: -- [text-to-image](./app/text-to-image_1_Wed%20Dec%2027%202023.json) -- [image-to-image](./app/image-to-image_1_Wed%20Dec%2027%202023.json) +- [text-to-image](./example/text-to-image_1_Wed%20Dec%2027%202023.json) +- [image-to-image](./example/image-to-image_1_Wed%20Dec%2027%202023.json) - text-to-text -> 暂时支持6种节点作为界面上的输入节点:Load Image、CLIPTextEncode、TextInput_、FloatSlider、CheckpointLoaderSimple、LoraLoader +> 暂时支持6种节点作为界面上的输入节点:Load Image、CLIPTextEncode、TextInput_、FloatSlider、IntNumber、CheckpointLoaderSimple、LoraLoader > 输出节点:PreviewImage 、SaveImage、ShowTextForGPT、VHS_VideoCombine diff --git a/__init__.py b/__init__.py index c277074..f53cc05 100644 --- a/__init__.py +++ b/__init__.py @@ -4,7 +4,7 @@ import subprocess import importlib.util import sys,json import urllib - +import hashlib import datetime @@ -79,6 +79,13 @@ install_openai() current_path = os.path.abspath(os.path.dirname(__file__)) + +def calculate_md5(string): + encoded_string = string.encode() + md5_hash = hashlib.md5(encoded_string).hexdigest() + return md5_hash + + def create_key(key_p,crt_p): import OpenSSL # 生成自签名证书 @@ -162,17 +169,75 @@ def get_workflows(): workflows=read_workflow_json_files(workflow_path) return workflows -def get_my_workflow_for_app(): - # print("#####path::", current_path) - workflow_path=os.path.join(current_path, "workflow/my_workflow_app.json") - print('workflow_path: ',workflow_path) - json_data={} - try: - with open(workflow_path) as json_file: - json_data = json.load(json_file) - except: - print('-') - return json_data +def get_my_workflow_for_app(filename="my_workflow_app.json"): + app_path=os.path.join(current_path, "app") + if not os.path.exists(app_path): + os.mkdir(app_path) + + apps=[] + if filename==None: + data=read_workflow_json_files(app_path) + i=0 + for item in data: + try: + x=item["data"] + if i==0: + apps.append({ + "filename":item["filename"], + "data":x, + "date":item["date"] + }) + else: + apps.append({ + "filename":item["filename"], + "data":{ + "app":{ + "description":x['app']['description'], + "filename":(x['app']['filename'] if 'filename' in x['app'] else "") , + "icon":(x['app']['icon'] if 'icon' in x['app'] else None), + "name":x['app']['name'], + "version":x['app']['version'], + } + }, + "date":item["date"] + }) + i+=1 + except Exception as e: + print("发生异常:", str(e)) + else: + app_workflow_path=os.path.join(app_path, filename) + # print('app_workflow_path: ',app_workflow_path) + try: + with open(app_workflow_path) as json_file: + apps = [{ + 'filename':filename, + 'data':json.load(json_file) + }] + except Exception as e: + print("发生异常:", str(e)) + + if len(apps)==1: + data=read_workflow_json_files(app_path) + + for item in data: + x=item["data"] + print(apps[0]['filename'] ,item["filename"]) + if apps[0]['filename']!=item["filename"]: + apps.append({ + "filename":item["filename"], + "data":{ + "app":{ + "description":x['app']['description'], + "filename":(x['app']['filename'] if 'filename' in x['app'] else "") , + "icon":(x['app']['icon'] if 'icon' in x['app'] else None), + "name":x['app']['name'], + "version":x['app']['version'], + } + }, + "date":item["date"] + }) + + return apps def save_workflow_json(data): workflow_path=os.path.join(current_path, "workflow/my_workflow.json") @@ -180,11 +245,22 @@ def save_workflow_json(data): json.dump(data, file) return workflow_path -def save_workflow_for_app(data): - workflow_path=os.path.join(current_path, "workflow/my_workflow_app.json") - with open(workflow_path, 'w') as file: +def save_workflow_for_app(data,filename="my_workflow_app.json"): + app_path=os.path.join(current_path, "app") + if not os.path.exists(app_path): + os.mkdir(app_path) + app_workflow_path=os.path.join(app_path, filename) + + try: + output_str = json.dumps(data['output']) + data['app']['id']=calculate_md5(output_str) + # id=data['app']['id'] + except Exception as e: + print("发生异常:", str(e)) + + with open(app_workflow_path, 'w') as file: json.dump(data, file) - return workflow_path + return filename def get_nodes_map(): # print("#####path::", current_path) @@ -295,14 +371,17 @@ async def mixlab_workflow_hander(request): 'file_path':file_path } elif data['task']=='save_app': - file_path=save_workflow_for_app(data['data']) + file_path=save_workflow_for_app(data['data'],data['filename']) result={ 'status':'success', 'file_path':file_path } elif data['task']=='my_app': + filename=None + if 'filename' in data: + filename=data['filename'] result={ - 'data':get_my_workflow_for_app(), + 'data':get_my_workflow_for_app(filename), 'status':'success', } elif data['task']=='list': @@ -359,7 +438,7 @@ PromptServer.add_routes=new_add_routes # 导入节点 from .nodes.PromptNode import RandomPrompt -from .nodes.ImageNode import NoiseImage,TransparentImage,LoadImagesFromPath,LoadImagesFromURL,ResizeImage,TextImage,SvgImage,Image3D,EmptyLayer,ShowLayer,NewLayer,MergeLayers,AreaToMask,SmoothMask,FeatheredMask,SplitLongMask,ImageCropByAlpha,EnhanceImage,FaceToMask +from .nodes.ImageNode import NoiseImage,TransparentImage,LoadImagesFromPath,LoadImagesFromURL,ResizeImage,TextImage,SvgImage,Image3D,ShowLayer,NewLayer,MergeLayers,AreaToMask,SmoothMask,FeatheredMask,SplitLongMask,ImageCropByAlpha,EnhanceImage,FaceToMask from .nodes.Vae import VAELoader,VAEDecode from .nodes.ScreenShareNode import ScreenShareNode,FloatingVideo from .nodes.Clipseg import CLIPSeg,CombineMasks diff --git a/assets/0-m-app.png b/assets/0-m-app.png new file mode 100644 index 0000000..c36f856 Binary files /dev/null and b/assets/0-m-app.png differ diff --git a/app/image-to-image_1_Wed Dec 27 2023.json b/example/image-to-image_1_Wed Dec 27 2023.json similarity index 100% rename from app/image-to-image_1_Wed Dec 27 2023.json rename to example/image-to-image_1_Wed Dec 27 2023.json diff --git a/app/text-to-image_1_Wed Dec 27 2023.json b/example/text-to-image_1_Wed Dec 27 2023.json similarity index 100% rename from app/text-to-image_1_Wed Dec 27 2023.json rename to example/text-to-image_1_Wed Dec 27 2023.json diff --git a/nodes/ChatGPT.py b/nodes/ChatGPT.py index 65a506d..5e08ee8 100644 --- a/nodes/ChatGPT.py +++ b/nodes/ChatGPT.py @@ -75,11 +75,11 @@ class ChatGPTNode: "required": { "api_key":("KEY", {"default": "", "multiline": True}), "api_url":("URL", {"default": "", "multiline": True}), - "prompt": ("STRING", {"multiline": True}), + "prompt": ("STRING", {"multiline": True,"dynamicPrompts": False}), "system_content": ("STRING", { "default": "You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible.", - "multiline": True + "multiline": True,"dynamicPrompts": False }), "model": (["gpt-3.5-turbo","gpt-35-turbo","gpt-3.5-turbo-16k", "gpt-3.5-turbo-16k-0613", "gpt-4-0613","gpt-4-1106-preview"], {"default": "gpt-3.5-turbo"}), @@ -167,7 +167,7 @@ class ShowTextForGPT: def INPUT_TYPES(s): return { "required": { - "text": ("STRING", {"forceInput": True}), + "text": ("STRING", {"forceInput": True,"dynamicPrompts": False}), } } @@ -189,8 +189,8 @@ class CharacterInText: def INPUT_TYPES(s): return { "required": { - "text": ("STRING", {"multiline": True}), - "character": ("STRING", {"multiline": True}), + "text": ("STRING", {"multiline": True,"dynamicPrompts": False}), + "character": ("STRING", {"multiline": True,"dynamicPrompts": False}), "start_index": ("INT", { "default": 1, "min": 0, #Minimum value diff --git a/nodes/Utils.py b/nodes/Utils.py index 65d4f61..6134c08 100644 --- a/nodes/Utils.py +++ b/nodes/Utils.py @@ -369,14 +369,14 @@ class AppInfo: @classmethod def INPUT_TYPES(s): return {"required": { - "name": ("STRING",{"multiline": False,"default": "Mixlab-App"}), + "name": ("STRING",{"multiline": False,"default": "Mixlab-App","dynamicPrompts": False}), "image": ("IMAGE",), - "input_ids":("STRING",{"multiline": True,"default": "\n".join(["1","2","3"])}), - "output_ids":("STRING",{"multiline": True,"default": "\n".join(["5","9"])}), + "input_ids":("STRING",{"multiline": True,"default": "\n".join(["1","2","3"]),"dynamicPrompts": False}), + "output_ids":("STRING",{"multiline": True,"default": "\n".join(["5","9"]),"dynamicPrompts": False}), }, "optional":{ - "description":("STRING",{"multiline": True,"default": ""}), + "description":("STRING",{"multiline": True,"default": "","dynamicPrompts": False}), "version":("INT", { "default": 1, "min": 1, @@ -384,6 +384,7 @@ class AppInfo: "step": 1, "display": "number" }), + "share_prefix":("STRING",{"multiline": False,"default": "","dynamicPrompts": False}), } } @@ -398,13 +399,13 @@ class AppInfo: INPUT_IS_LIST = False OUTPUT_IS_LIST = (False,) - def run(self,name,image,input_ids,output_ids,description,version): + def run(self,name,image,input_ids,output_ids,description,version,share_prefix): im=create_temp_file(image) # id=get_json_hash([name,im,input_ids,output_ids,description,version]) - return {"ui": {"json": [name,im,input_ids,output_ids,description,version]}, "result": (image,)} + return {"ui": {"json": [name,im,input_ids,output_ids,description,version,share_prefix]}, "result": (image,)} diff --git a/web/index.html b/web/index.html index 2e60eb6..05afdc8 100644 --- a/web/index.html +++ b/web/index.html @@ -13,7 +13,77 @@ margin-left: 5%; } + .apps { + margin: 0 32px; + background: whitesmoke; + color: black; + padding: 12px; + cursor: pointer; + } + .apps .content { + display: flex; + flex-wrap: wrap; + } + + + .apps .card { + width: 200px; + margin: 12px; + display: flex; + flex-direction: row; + background: #f8f8f8; + cursor: pointer; + user-select: none; + } + + .apps .selected { + box-shadow: 0px 0px 10px 10px #fbe9f0 + } + + .apps .card:hover { + box-shadow: 0px 0px 10px 10px #e9fbfa + } + + .apps .card h5 { + font-size: 14px; + margin: 10px 0; + } + + .apps .card p { + margin: 0; + padding: 0; + } + + .apps .card img { + width: auto; + height: 100%; + + margin: 0px; + } + + .apps .card .item { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + } + + .apps .card .icon { + width: 120px; + height: 120px; + overflow: hidden; + background: #e3e3e3; + display: flex; + justify-content: center; + align-items: center; + } + + + .apps .card .version { + font-size: 12px; + + } .status { background: black; @@ -42,17 +112,24 @@ display: flex; flex-direction: column; min-width: 400px; - background: #eee; + /* background: #eee; */ margin: 24px; flex: 1; align-items: center; /* justify-content: center; */ } + .panel .header { + margin-bottom: 8px; + display: flex; + justify-content: center; + align-items: center; + + } + .panel h1 { padding: 0 12px; - margin-top: 12px; - margin-bottom: 0; + margin: 0; } .panel img, @@ -68,13 +145,18 @@ flex-direction: column; } + .output { + width: 90%; + margin: 12px; + } + .output_card { height: 100%; width: 100%; - box-shadow: 0px 0px 8px 3px #e6e7e7; - + box-shadow: 0px 0px 20px 7px #e6e7e7; + margin-top: 24px; display: flex; - + flex-wrap: wrap; /* justify-content: center; align-items: center; */ @@ -84,6 +166,8 @@ video { max-width: 400px; max-height: 600px; + margin: 8px; + min-width: 200px; } .card { @@ -125,7 +209,7 @@ border: 3px solid; } - .run_btn:hover { + button:hover { border-color: yellow; color: yellow; } @@ -138,28 +222,28 @@ .upload_btn { width: 188px; cursor: pointer; - height: 188px; - background: black; + /* height: 188px; */ + /* background: black; */ color: white; display: flex; justify-content: center; align-items: center; text-align: center; font-size: 14px; - margin-left: calc(50% - 94px); - margin-top: calc(30vh - 94px); + color: black; } - .upload_btn:hover { + /* .upload_btn:hover { outline: 4px solid yellow; color: yellow; - } + } */ .show_text { font-size: 14px; /* display: inline-block; */ - /* margin: 13px; */ + margin: 8px; padding: 32px; + min-width: 200px; background: #242424; color: white; } @@ -170,15 +254,39 @@ font-size: 12px; font-weight: 300; } + + label::after { + content: attr(data-content); + /* Set the initial content using the data-content attribute */ + /* position: absolute; */ + /* top: 100%; + left: 0; */ + margin-left: 4px; + font-size: 12px; + color: #555; + } + + select, + button, + input { + height: 32px; + cursor: pointer; + background: #000000bf; + color: white; + outline: none; + border: none; + border-radius: 4px; + } -
Explore your creative potential with Explore your creative potential with mixlab-nodes / 尽情发挥你的创意
ComfyUI中文爱好者社区推荐 @@ -258,46 +366,104 @@ }); } - async function get_my_app() { + + function success(isSuccess, btn, text) { + isSuccess ? btn.innerText = 'success' : text; + setTimeout(() => { + btn.innerText = text; + }, 5000) + } + + async function get_my_app(filename = null) { let url = get_url() const res = await fetch(`${url}/mixlab/workflow`, { method: 'POST', body: JSON.stringify({ - task: 'my_app' + task: 'my_app', + filename }) }) let result = await res.json(); + let data = []; + try { + for (const res of result.data) { + let { output, app } = res.data; + if (app.filename) data.push({ + ...app, + data: output, + date: res.date + }) + } + } catch (error) { - let { output, app } = result.data - - return { - ...app, - data: output } + + + return data } function createOutputs(outputData) { - // Array.from( window._appData.output,n=>n.id) - const container = document.createElement("div"); - container.className = 'output_card' + const container = document.createElement('div'); + container.className = "output"; + + const action = document.createElement('div'); + container.appendChild(action) + + const copyHTML = document.createElement('button'); + copyHTML.innerText = 'copy as html' + action.appendChild(copyHTML) + + const copyImage = document.createElement('button'); + copyImage.innerText = 'copy image' + action.appendChild(copyImage) + copyImage.style.marginLeft = '18px'; + + const copyText = document.createElement('button'); + copyText.innerText = 'copy text for share' + action.appendChild(copyText) + copyText.style.marginLeft = '18px'; + + const output_card = document.createElement("div"); + output_card.className = 'output_card' + container.appendChild(output_card) + + + + copyText.addEventListener('click', e => { + e.preventDefault(); + copyTextToClipboard((window._appData.share_prefix || '') + " " + output_card.outerHTML, (r) => success(r, copyText, 'copy text for share')) + + }) + + copyImage.addEventListener('click', e => { + e.preventDefault(); + // copyHtmlWithImagesToClipboard(output_card.outerHTML) + copyImagesToClipboard(output_card.outerHTML, (r) => success(r, copyImage, 'copy image')) + // copyTextToClipboard() + }) + copyHTML.addEventListener('click', e => { + e.preventDefault(); + copyHtmlWithImagesToClipboard((window._appData.share_prefix || '') + " " + output_card.outerHTML, (r) => success(r, copyHTML, 'copy as html')) + // copyImagesToClipboard(output_card.outerHTML) + }) for (const node of outputData) { - console.log('output', node) + // console.log('output', node) if (node.class_type == "ShowTextForGPT") { let div = document.createElement('div'); div.className = "show_text" div.id = `output_${node.id}`; - div.innerText = node.inputs.text[0] - container.appendChild(div); + div.innerText = Array.isArray(node.inputs.text) ? node.inputs.text[0] : node.inputs.text + output_card.appendChild(div); }; if (["SaveImage", "PreviewImage"].includes(node.class_type)) { let img = new Image(); img.id = `output_${node.id}`; img.src = base64Df; - container.appendChild(img); + output_card.appendChild(img); } // video ,gif @@ -313,7 +479,7 @@ v.appendChild(video); v.appendChild(img); - container.appendChild(v); + output_card.appendChild(v); } } @@ -362,6 +528,134 @@ } } + + function copyHtmlWithImagesToClipboard(data, cb) { + // 创建一个临时div元素 + const tempDiv = document.createElement('div'); + + // 将HTML字符串赋值给div的innerHTML属性 + tempDiv.innerHTML = data; + + // 获取div中的所有图像元素 + const images = tempDiv.getElementsByTagName('img'); + + // 遍历图像元素,并将图像数据转换为Base64编码 + for (let i = 0; i < images.length; i++) { + const image = images[i]; + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + + // 设置canvas尺寸与图像尺寸相同 + canvas.width = image.width; + canvas.height = image.height; + + // 在canvas上绘制图像 + context.drawImage(image, 0, 0); + + // 将canvas转换为Base64编码 + const imageData = canvas.toDataURL(); + + // 将Base64编码替换图像元素的src属性 + image.src = imageData; + } + + + let richText = tempDiv.innerHTML; + + // 创建一个新的Blob对象,并将富文本字符串作为数据传递进去 + const blob = new Blob([richText], { type: 'text/html' }); + + // 创建一个ClipboardItem对象,并将Blob对象添加到其中 + const clipboardItem = new ClipboardItem({ 'text/html': blob }); + + // 使用Clipboard API将内容复制到剪贴板 + navigator.clipboard.write([clipboardItem]) + .then(() => { + console.log('富文本已成功复制到剪贴板'); + tempDiv.remove() + if (cb) cb(true) + }) + .catch((error) => { + console.error('复制到剪贴板失败:', error); + tempDiv.remove() + if (cb) cb(false) + }); + + } + + // const htmlWithImages = "

这是要复制的HTML内容

" + // copyHtmlWithImagesToClipboard(htmlWithImages); + + function copyImagesToClipboard(html, cb) { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + const images = tempDiv.querySelectorAll('img'); + const promises = Array.from(images).map((image) => { + return new Promise((resolve) => { + const img = new Image(); + img.src = image.src; + img.onload = () => { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + canvas.width = img.width; + canvas.height = img.height; + context.drawImage(img, 0, 0); + canvas.toBlob((blob) => { + const clipboardItem = new ClipboardItem({ 'image/png': blob }); + navigator.clipboard.write([clipboardItem]) + .then(() => { + resolve(); + tempDiv.remove() + if (cb) cb(true) + }) + .catch((error) => { + reject(error); + tempDiv.remove() + if (cb) cb(false) + }); + }); + }; + }); + }); + Promise.all([...promises]) + .then(() => { + console.log('所有图片已成功复制到剪贴板'); + if (cb) cb(true) + tempDiv.remove() + }) + .catch((error) => { + console.error('复制到剪贴板失败:', error); + if (cb) cb(false) + tempDiv.remove() + }); + } + + function copyTextToClipboard(html, cb) { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = html; + + const text = tempDiv.innerText; + const textData = new ClipboardItem({ 'text/plain': new Blob([text], { type: 'text/plain' }) }); + + navigator.clipboard.write([textData]) + .then(() => { + console.log('所有文本已成功复制到剪贴板', text); + if (cb) cb(true) + tempDiv.remove() + }) + .catch((error) => { + console.error('复制到剪贴板失败:', error); + if (cb) cb(false) + tempDiv.remove() + }); + } + + + // const htmlString = "

这是要复制的HTML内容

"; + // copyImagesToClipboard(htmlString); + + + function createInputs(inputData) { // Assuming you have an HTML element with the id "container" to hold the UI const container = document.createElement("div"); @@ -393,6 +687,7 @@ // Create a label for the upload control const nameLabel = document.createElement("label"); nameLabel.textContent = data.title || "LoadImage: "; + nameLabel.style.marginBottom = '12px' uploadContainer.appendChild(nameLabel); let actionDiv = document.createElement('div'); @@ -408,9 +703,7 @@ actionDiv.appendChild(uploadImageInputHide); const btnFromClipboard = document.createElement("button"); - btnFromClipboard.style = `width: 156px; - height: 24px; - margin-left: 18px;` + btnFromClipboard.style = `width: 156px; margin-left: 18px;` btnFromClipboard.innerText = 'paste from clipboard' actionDiv.appendChild(btnFromClipboard); @@ -469,9 +762,14 @@ if (['FloatSlider', 'IntNumber'].includes(data.class_type)) { // 滑块输入 - let silde = createFloatSlide(data.title, data.inputs.number, (v) => { - window._appData.data[data.id].inputs.number = v; - }) + let silde = createNumSlide(data.title, + data.inputs.number, + (v) => { + window._appData.data[data.id].inputs.number = v; + }, + 0, + data.class_type === 'IntNumber' ? 6000 : 1, + data.class_type === 'IntNumber' ? 'int' : 'float') container.appendChild(silde); } @@ -537,19 +835,20 @@ return container } - function createFloatSlide(labelText, value = 0, callback, minValue = 0, maxValue = 1) { + function createNumSlide(labelText, value = 0, callback, minValue = 0, maxValue = 1, type = 'float') { // 创建滑块输入元素 var slider = document.createElement("input"); slider.type = "range"; slider.min = minValue; slider.max = maxValue; - slider.step = 0.01 + slider.step = type == 'float' ? 0.01 : 1 slider.value = value; // 创建标签元素 var label = document.createElement("label"); label.innerHTML = labelText; + label.setAttribute('data-content', value); // 创建容器元素,并将滑块输入和标签添加到容器中 var container = document.createElement("div"); @@ -558,9 +857,11 @@ container.className = 'card' // 添加change事件监听器 - slider.addEventListener("change", function (event) { + slider.addEventListener("input", function (event) { var value = event.target.value; + value = type == 'float' ? value : Math.round(value) console.log("滑块输入的值为:" + value); + label.setAttribute('data-content', value); // 在这里可以执行其他操作,根据需要进行相应的处理 callback && callback(value) }); @@ -599,21 +900,21 @@ return [div, selectElement]; } - function getTypeFromUrl(url) { + function getFilenameFromUrl(url) { const queryString = url.split('?')[1]; if (!queryString) { return null; } const params = new URLSearchParams(queryString); - const type = params.get('type'); + const filename = decodeURIComponent(params.get('filename')); - return type; + return filename; } - function createUI(inputData, outputData) { + function createUI(inputData, outputData, share = true) { let mainDiv = document.createElement('div'); let leftDiv = document.createElement('div'); @@ -631,8 +932,26 @@ // top: 12px;flex:0.6` // 创建标题 + let titleDiv = document.createElement('div'); + titleDiv.className = 'header' + var title = document.createElement('h1'); title.textContent = 'My Application'; + titleDiv.appendChild(title); + + if (share) { + const shareBtn = document.createElement('button'); + shareBtn.innerText = 'copy url'; + shareBtn.addEventListener('click', e => { + e.preventDefault(); + let url = `${get_url()}/mixlab/app?filename=${encodeURIComponent(window._appData.filename)}`; + copyTextToClipboard(url, success(e, shareBtn, 'copy url')); + }) + + titleDiv.appendChild(shareBtn); + } + + let iconDes = document.createElement('div'); // 创建应用图标 @@ -663,7 +982,7 @@ submitButton.className = 'run_btn' // 将所有UI元素添加到页面中 - leftDiv.appendChild(title); + leftDiv.appendChild(titleDiv); leftDiv.appendChild(iconDes); // leftDiv.appendChild(des); leftDiv.appendChild(status); @@ -750,16 +1069,16 @@ }); } - } + }, }; } - function createUploadJson() { + function createUploadJson(detail) { // 创建一个div元素 var div = document.createElement('div'); - div.className = 'upload_btn' - div.textContent = '点击上传JSON文件'; + div.className = 'upload_btn card' + div.textContent = '上传并运行你的JSON文件'; div.addEventListener('click', function () { document.getElementById('jsonFileInput').click(); }); @@ -775,10 +1094,11 @@ reader.onload = function (e) { var contents = e.target.result; var jsonData = JSON.parse(contents); - setTimeout(() => { - div.remove(); - input.remove(); - }, 500); + + + Array.from(detail.querySelectorAll('.card'), c => c.classList.remove('selected')); + div.className = 'upload_btn card selected' + let { output, app } = jsonData; @@ -786,8 +1106,8 @@ ...app, data: output }; - - createApp(window._appData); + if (document.body.querySelector('.app')) document.body.querySelector('.app').remove() + createApp(window._appData, false); // res(jsonData); }; @@ -795,16 +1115,16 @@ }); // 将div和input元素添加到body中 - document.body.appendChild(div); + // document.body.appendChild(div); document.body.appendChild(input); - - + return div } - async function createApp(appData) { + async function createApp(appData, share = true) { + console.log(appData) // 使用示例: - var ui = createUI(appData.input, appData.output); + var ui = createUI(appData.input, appData.output, share); // 更新标题 ui.title.update(appData.name || 'Mixlab APP'); @@ -859,8 +1179,8 @@ // if (!images) return; const src = `${get_url()}/view?filename=${encodeURIComponent(images[0].filename)}&type=${images[0].type}&subfolder=${encodeURIComponent(images[0].subfolder)}&t=${+new Date()}`; show(src, detail.node, 'image'); - } else if (text && text[0]) { - ui.output.update("text", text[0], detail.node) + } else if (text) { + ui.output.update("text", Array.isArray(text) ? text[0] : text, detail.node) } else if (gifs && gifs[0]) { // if (!images) return; const src = `${get_url()}/view?filename=${encodeURIComponent(gifs[0].filename)}&type=${gifs[0].type}&subfolder=${encodeURIComponent(gifs[0].subfolder) @@ -886,24 +1206,72 @@ api.api_base = "" api.init(); + } + // 创建app的选择菜单 + function createAppList(apps = []) { + let details = document.createElement('details'); + details.className = 'apps'; + + details.innerHTML = `ComfyUI APP Store / ${apps.length} +
` + + let div = details.querySelector('div'); + + for (let index = 0; index < apps.length; index++) { + const app = apps[index]; + let d = document.createDocumentFragment(); + let dd = document.createElement('div'); + d.appendChild(dd); + dd.className = 'card' + (index == 0 ? ' selected' : '') + dd.innerHTML = ` +
+ +
+
+
+
${app.name}
+

${app.description}

+
+
+

version: ${app.version}

+ +
+
+ ` + + div.appendChild(d); + dd.addEventListener('click', async e => { + e.preventDefault(); + Array.from(div.querySelectorAll('.card'), c => c.classList.remove('selected')); + dd.className = 'card selected' + // console.log(app.filename) + + window._appData = (await get_my_app(app.filename))[0]; + if (document.body.querySelector('.app')) document.body.querySelector('.app').remove() + createApp(window._appData); + + }) + // console.log(div) + }; + + let uploadApp = createUploadJson(details); + div.appendChild(uploadApp); + + document.body.appendChild(details); + } async function init_app() { - let appData = {} + const filename = getFilenameFromUrl(location.href); + window._apps = await get_my_app(filename); - const type = getTypeFromUrl(location.href); - if (type === 'new') { - createUploadJson(); - } else { - appData = await get_my_app(); - // console.log(appData) - window._appData = appData; + window._appData = window._apps[0]; - createApp(appData); - } + createAppList(window._apps); + createApp(window._appData); }; diff --git a/web/javascript/app_mixlab.js b/web/javascript/app_mixlab.js index 454cdcd..6af907c 100644 --- a/web/javascript/app_mixlab.js +++ b/web/javascript/app_mixlab.js @@ -81,8 +81,9 @@ function extractInputAndOutputData (jsonData, inputIds = [], outputIds = []) { if (node.type === 'CheckpointLoaderSimple') { options = node.widgets.filter(w => w.name === 'ckpt_name')[0] .options.values - }else if(node.type === 'LoraLoader'){ - options =node.widgets.filter(w=>w.name==='lora_name')[0].options.values + } else if (node.type === 'LoraLoader') { + options = node.widgets.filter(w => w.name === 'lora_name')[0] + .options.values } } catch (error) {} @@ -119,7 +120,8 @@ async function save_app (json) { method: 'POST', body: JSON.stringify({ data: json, - task: 'save_app' + task: 'save_app', + filename: json.app.filename }) }) return await res.json() @@ -144,6 +146,7 @@ function downloadJsonFile (jsonData, fileName = 'mix_app.json') { async function save (json, download = false) { const name = json[0], version = json[5], + share_prefix = json[6], //用于分享的功能扩展 description = json[4], inputIds = json[2].split('\n').filter(f => f), outputIds = json[3].split('\n').filter(f => f) @@ -170,7 +173,9 @@ async function save (json, download = false) { description, version, input, - output + output, + share_prefix, + filename: `${name}_${version}_${new Date().toDateString()}.json` } try { @@ -180,14 +185,15 @@ async function save (json, download = false) { // let http_workflow = app.graph.serialize() if (download) { - await downloadJsonFile( - data, - `${data.app.name}_${data.app.version}_${new Date().toDateString()}.json` - ) + await save_app(data) + await downloadJsonFile(data, data.app.filename) let open = window.confirm( - `You can now access the standalone application on a new page!\n${getUrl()}/mixlab/app?type=new` + `You can now access the standalone application on a new page!\n${getUrl()}/mixlab/app?filename=${encodeURIComponent(data.app.filename)}` ) - if (open) window.open(`${getUrl()}/mixlab/app?type=new`) + if (open) + window.open( + `${getUrl()}/mixlab/app?filename=${encodeURIComponent(data.app.filename)}` + ) } else { await save_app(data) @@ -208,7 +214,7 @@ app.registerExtension({ const orig_nodeCreated = nodeType.prototype.onNodeCreated nodeType.prototype.onNodeCreated = function () { orig_nodeCreated?.apply(this, arguments) - // console.log(this) + console.log('#orig_nodeCreated', this) const widget = { type: 'div', name: 'AppInfoRun', @@ -218,7 +224,7 @@ app.registerExtension({ get_position_style( ctx, widget_width, - node.widgets[4].last_y + 24, + node.size[1] - widget_height, node.size[1] ) ) @@ -236,7 +242,7 @@ app.registerExtension({ widget.div = $el('div', {}) const btn = document.createElement('button') - btn.innerText = 'Save For App' + btn.innerText = 'Save & Open' btn.style = style btn.addEventListener('click', () => { @@ -246,6 +252,7 @@ app.registerExtension({ } else { alert('Please run the workflow before saving') // app.queuePrompt(0, 1) + this.widgets.filter(w => w.name === 'version')[0].value += 1 } }) @@ -261,6 +268,7 @@ app.registerExtension({ } else { alert('Please run the workflow before saving') // app.queuePrompt(0, 1) + this.widgets.filter(w => w.name === 'version')[0].value += 1 } }) @@ -282,7 +290,7 @@ app.registerExtension({ const onExecuted = nodeType.prototype.onExecuted nodeType.prototype.onExecuted = async function (message) { onExecuted?.apply(this, arguments) - // console.log(this.widgets) + console.log(message.json) window._mixlab_app_json = message.json try { diff --git a/web/javascript/checkVersion_mixlab.js b/web/javascript/checkVersion_mixlab.js index 1b94800..e98c585 100644 --- a/web/javascript/checkVersion_mixlab.js +++ b/web/javascript/checkVersion_mixlab.js @@ -3,7 +3,7 @@ import { app } from '../../../scripts/app.js' const repoOwner = 'shadowcz007' // 替换为仓库的所有者 const repoName = 'comfyui-mixlab-nodes' // 替换为仓库的名称 -const version = 'v0.6.0' +const version = 'v0.7.0' fetch(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`) .then(response => response.json()) diff --git a/workflow/3D-workflow.json b/workflow/3D-workflow.json index 54ba842..00389a6 100644 --- a/workflow/3D-workflow.json +++ b/workflow/3D-workflow.json @@ -1,6 +1,6 @@ { - "last_node_id": 60, - "last_link_id": 118, + "last_node_id": 65, + "last_link_id": 143, "nodes": [ { "id": 9, @@ -52,7 +52,7 @@ "1": 246 }, "flags": {}, - "order": 31, + "order": 29, "mode": 0, "inputs": [ { @@ -77,7 +77,7 @@ "1": 26 }, "flags": {}, - "order": 20, + "order": 18, "mode": 0, "inputs": [ { @@ -168,8 +168,7 @@ "name": "VAE", "type": "VAE", "links": [ - 11, - 23 + 11 ], "slot_index": 2 } @@ -219,70 +218,6 @@ " a metallic sash-like shoe,render by ue5,and blender,8k,detailed" ] }, - { - "id": 2, - "type": "PreviewImage", - "pos": [ - 673.0796203613281, - 734.9191284179688 - ], - "size": { - "0": 210, - "1": 246 - }, - "flags": {}, - "order": 8, - "mode": 0, - "inputs": [ - { - "name": "images", - "type": "IMAGE", - "link": 76 - } - ], - "properties": { - "Node name for S&R": "PreviewImage" - } - }, - { - "id": 17, - "type": "VAEEncode", - "pos": [ - 673.0796203613281, - 1110.9191284179688 - ], - "size": { - "0": 210, - "1": 46 - }, - "flags": {}, - "order": 9, - "mode": 0, - "inputs": [ - { - "name": "pixels", - "type": "IMAGE", - "link": 77 - }, - { - "name": "vae", - "type": "VAE", - "link": 23 - } - ], - "outputs": [ - { - "name": "LATENT", - "type": "LATENT", - "links": [], - "shape": 3, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "VAEEncode" - } - }, { "id": 43, "type": "IPAdapterModelLoader", @@ -328,7 +263,7 @@ "flags": { "collapsed": false }, - "order": 35, + "order": 33, "mode": 0, "inputs": [ { @@ -368,13 +303,13 @@ "1": 106 }, "flags": {}, - "order": 15, + "order": 13, "mode": 0, "inputs": [ { "name": "width", "type": "INT", - "link": 26, + "link": 120, "widget": { "name": "width" }, @@ -383,7 +318,7 @@ { "name": "height", "type": "INT", - "link": 27, + "link": 121, "widget": { "name": "height" } @@ -420,7 +355,7 @@ "1": 26 }, "flags": {}, - "order": 26, + "order": 24, "mode": 0, "inputs": [ { @@ -454,7 +389,7 @@ "1": 58 }, "flags": {}, - "order": 21, + "order": 19, "mode": 0, "inputs": [ { @@ -494,18 +429,18 @@ "1": 130 }, "flags": {}, - "order": 17, + "order": 15, "mode": 0, "inputs": [ { "name": "image", "type": "IMAGE", - "link": 82 + "link": 137 }, { "name": "width", "type": "INT", - "link": 46, + "link": 124, "widget": { "name": "width" } @@ -513,7 +448,7 @@ { "name": "height", "type": "INT", - "link": 47, + "link": 125, "widget": { "name": "height" } @@ -550,7 +485,7 @@ "1": 246 }, "flags": {}, - "order": 25, + "order": 23, "mode": 0, "inputs": [ { @@ -575,13 +510,13 @@ "1": 130 }, "flags": {}, - "order": 18, + "order": 16, "mode": 0, "inputs": [ { "name": "width", "type": "INT", - "link": 102, + "link": 126, "widget": { "name": "width" } @@ -589,7 +524,7 @@ { "name": "height", "type": "INT", - "link": 97, + "link": 127, "widget": { "name": "height" } @@ -615,199 +550,6 @@ 0 ] }, - { - "id": 50, - "type": "PreviewImage", - "pos": [ - 673.0796203613281, - 1698.9191284179688 - ], - "size": { - "0": 210, - "1": 246 - }, - "flags": {}, - "order": 12, - "mode": 0, - "inputs": [ - { - "name": "images", - "type": "IMAGE", - "link": 87 - } - ], - "properties": { - "Node name for S&R": "PreviewImage" - } - }, - { - "id": 20, - "type": "MergeLayers", - "pos": [ - 1613.3576354980469, - 694 - ], - "size": { - "0": 210, - "1": 46 - }, - "flags": {}, - "order": 23, - "mode": 0, - "inputs": [ - { - "name": "layers", - "type": "LAYER", - "link": 103, - "slot_index": 0 - }, - { - "name": "image", - "type": "IMAGE", - "link": 110 - } - ], - "outputs": [ - { - "name": "IMAGE", - "type": "IMAGE", - "links": [ - 34, - 36 - ], - "shape": 3, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "MergeLayers" - } - }, - { - "id": 22, - "type": "NewLayer", - "pos": [ - 1198.3576354980469, - 366 - ], - "size": { - "0": 315, - "1": 234 - }, - "flags": {}, - "order": 16, - "mode": 0, - "inputs": [ - { - "name": "image", - "type": "IMAGE", - "link": 74 - }, - { - "name": "mask", - "type": "MASK", - "link": 75 - }, - { - "name": "layers", - "type": "LAYER", - "link": null, - "slot_index": 2 - }, - { - "name": "width", - "type": "INT", - "link": 30, - "widget": { - "name": "width" - } - }, - { - "name": "height", - "type": "INT", - "link": 31, - "widget": { - "name": "height" - } - } - ], - "outputs": [ - { - "name": "layers", - "type": "LAYER", - "links": [ - 103 - ], - "shape": 6, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "NewLayer" - }, - "widgets_values": [ - 0, - 0, - 512, - 512, - 2, - "width", - "" - ] - }, - { - "id": 18, - "type": "GetImageSize", - "pos": [ - 673.0796203613281, - 1286.9191284179688 - ], - "size": { - "0": 210, - "1": 46 - }, - "flags": {}, - "order": 10, - "mode": 0, - "inputs": [ - { - "name": "image", - "type": "IMAGE", - "link": 78 - } - ], - "outputs": [ - { - "name": "width", - "type": "INT", - "links": [ - 26, - 30, - 46, - 102, - 106 - ], - "shape": 3, - "slot_index": 0 - }, - { - "name": "height", - "type": "INT", - "links": [ - 27, - 31, - 47, - 97, - 107 - ], - "shape": 3, - "slot_index": 1 - } - ], - "properties": { - "Node name for S&R": "GetImageSize" - } - }, { "id": 57, "type": "PreviewImage", @@ -820,7 +562,7 @@ "1": 246 }, "flags": {}, - "order": 22, + "order": 20, "mode": 0, "inputs": [ { @@ -845,7 +587,7 @@ "1": 82 }, "flags": {}, - "order": 24, + "order": 21, "mode": 0, "inputs": [ { @@ -886,7 +628,7 @@ "1": 309.7566223144531 }, "flags": {}, - "order": 29, + "order": 25, "mode": 0, "inputs": [ { @@ -911,7 +653,7 @@ "1": 98 }, "flags": {}, - "order": 33, + "order": 31, "mode": 0, "inputs": [ { @@ -961,13 +703,13 @@ "1": 529.5877685546875 }, "flags": {}, - "order": 28, + "order": 26, "mode": 0, "inputs": [ { "name": "images", "type": "IMAGE", - "link": 36 + "link": 142 } ], "properties": { @@ -986,13 +728,13 @@ "1": 26 }, "flags": {}, - "order": 13, + "order": 11, "mode": 0, "inputs": [ { "name": "mask", "type": "MASK", - "link": 80 + "link": 136 } ], "outputs": [ @@ -1011,174 +753,6 @@ "Node name for S&R": "InvertMask" } }, - { - "id": 26, - "type": "CannyEdgePreprocessor", - "pos": [ - 673.0796203613281, - 1462.9191284179688 - ], - "size": { - "0": 315, - "1": 106 - }, - "flags": {}, - "order": 11, - "mode": 0, - "inputs": [ - { - "name": "image", - "type": "IMAGE", - "link": 79 - } - ], - "outputs": [ - { - "name": "IMAGE", - "type": "IMAGE", - "links": [ - 40 - ], - "shape": 3, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "CannyEdgePreprocessor" - }, - "widgets_values": [ - 126, - 200, - 512 - ] - }, - { - "id": 56, - "type": "ImageScale", - "pos": [ - 1198.3576354980469, - 1234 - ], - "size": { - "0": 315, - "1": 130 - }, - "flags": {}, - "order": 19, - "mode": 0, - "inputs": [ - { - "name": "image", - "type": "IMAGE", - "link": 108 - }, - { - "name": "width", - "type": "INT", - "link": 106, - "widget": { - "name": "width" - } - }, - { - "name": "height", - "type": "INT", - "link": 107, - "widget": { - "name": "height" - } - } - ], - "outputs": [ - { - "name": "IMAGE", - "type": "IMAGE", - "links": [ - 109, - 110, - 117 - ], - "shape": 3, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "ImageScale" - }, - "widgets_values": [ - "nearest-exact", - 512, - 512, - "disabled" - ] - }, - { - "id": 42, - "type": "IPAdapterApply", - "pos": [ - 673.0796203613281, - 2230.9191284179688 - ], - "size": { - "0": 315, - "1": 258 - }, - "flags": {}, - "order": 14, - "mode": 0, - "inputs": [ - { - "name": "ipadapter", - "type": "IPADAPTER", - "link": 67, - "slot_index": 0 - }, - { - "name": "clip_vision", - "type": "CLIP_VISION", - "link": 68, - "slot_index": 1 - }, - { - "name": "image", - "type": "IMAGE", - "link": 83, - "slot_index": 2 - }, - { - "name": "model", - "type": "MODEL", - "link": 70 - }, - { - "name": "attn_mask", - "type": "MASK", - "link": null - } - ], - "outputs": [ - { - "name": "MODEL", - "type": "MODEL", - "links": [ - 71 - ], - "shape": 3, - "slot_index": 0 - } - ], - "properties": { - "Node name for S&R": "IPAdapterApply" - }, - "widgets_values": [ - 0.9, - 0, - "linear", - 0, - 0.886, - false - ] - }, { "id": 27, "type": "ControlNetApply", @@ -1191,7 +765,7 @@ "1": 98 }, "flags": {}, - "order": 32, + "order": 30, "mode": 0, "inputs": [ { @@ -1311,7 +885,7 @@ { "name": "image", "type": "IMAGE", - "link": 34 + "link": 143 }, { "name": "mask", @@ -1347,7 +921,7 @@ "1": 98 }, "flags": {}, - "order": 30, + "order": 28, "mode": 0, "inputs": [ { @@ -1398,7 +972,7 @@ "1": 262 }, "flags": {}, - "order": 34, + "order": 32, "mode": 0, "inputs": [ { @@ -1447,17 +1021,268 @@ ] }, { - "id": 45, - "type": "3DImage", + "id": 61, + "type": "GetImageSize_", "pos": [ - -981, - 1174 + 575, + 1151 ], "size": { - "0": 473.0796203613281, - "1": 451.867919921875 + "0": 210, + "1": 46 }, "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 133 + } + ], + "outputs": [ + { + "name": "width", + "type": "INT", + "links": [ + 120, + 122, + 124, + 126, + 128 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "height", + "type": "INT", + "links": [ + 121, + 123, + 125, + 127, + 129 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "GetImageSize_" + } + }, + { + "id": 56, + "type": "ImageScale", + "pos": [ + 1167, + 1211 + ], + "size": { + "0": 315, + "1": 130 + }, + "flags": {}, + "order": 17, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 138 + }, + { + "name": "width", + "type": "INT", + "link": 128, + "widget": { + "name": "width" + } + }, + { + "name": "height", + "type": "INT", + "link": 129, + "widget": { + "name": "height" + } + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 109, + 117, + 141 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "ImageScale" + }, + "widgets_values": [ + "nearest-exact", + 512, + 512, + "disabled" + ] + }, + { + "id": 22, + "type": "NewLayer", + "pos": [ + 1198, + 366 + ], + "size": { + "0": 315, + "1": 234 + }, + "flags": {}, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 132 + }, + { + "name": "mask", + "type": "MASK", + "link": 135 + }, + { + "name": "layers", + "type": "LAYER", + "link": null, + "slot_index": 2 + }, + { + "name": "width", + "type": "INT", + "link": 122, + "widget": { + "name": "width" + } + }, + { + "name": "height", + "type": "INT", + "link": 123, + "widget": { + "name": "height" + } + } + ], + "outputs": [ + { + "name": "layers", + "type": "LAYER", + "links": [ + 140 + ], + "shape": 6, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "NewLayer" + }, + "widgets_values": [ + 0, + 0, + 512, + 512, + 2, + "width", + "" + ] + }, + { + "id": 64, + "type": "PreviewImage", + "pos": [ + 630, + 674 + ], + "size": [ + 210, + 246 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 131 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 26, + "type": "CannyEdgePreprocessor", + "pos": [ + 673.0796203613281, + 1462.9191284179688 + ], + "size": { + "0": 315, + "1": 106 + }, + "flags": {}, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 134 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 40 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "CannyEdgePreprocessor" + }, + "widgets_values": [ + 126, + 200, + 512 + ] + }, + { + "id": 63, + "type": "3DImage", + "pos": [ + -707, + 963 + ], + "size": [ + 315, + 486 + ], + "flags": {}, "order": 5, "mode": 0, "inputs": [ @@ -1472,12 +1297,10 @@ "name": "IMAGE", "type": "IMAGE", "links": [ - 74, - 76, - 77, - 78, - 79, - 87 + 131, + 132, + 133, + 134 ], "shape": 3, "slot_index": 0 @@ -1486,8 +1309,8 @@ "name": "MASK", "type": "MASK", "links": [ - 75, - 80 + 135, + 136 ], "shape": 3, "slot_index": 1 @@ -1496,9 +1319,9 @@ "name": "BG_IMAGE", "type": "IMAGE", "links": [ - 82, - 83, - 108 + 137, + 138, + 139 ], "shape": 3, "slot_index": 2 @@ -1514,19 +1337,61 @@ "Node name for S&R": "3DImage" } }, + { + "id": 65, + "type": "MergeLayers", + "pos": [ + 1651, + 674 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": {}, + "order": 22, + "mode": 0, + "inputs": [ + { + "name": "layers", + "type": "LAYER", + "link": 140 + }, + { + "name": "images", + "type": "IMAGE", + "link": 141 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 142, + 143 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "MergeLayers" + } + }, { "id": 15, "type": "PreviewImage", "pos": [ -456, - 1945 + 1756 ], "size": { "0": 439.2066345214844, "1": 539.8549194335938 }, "flags": {}, - "order": 36, + "order": 34, "mode": 0, "inputs": [ { @@ -1538,6 +1403,73 @@ "properties": { "Node name for S&R": "PreviewImage" } + }, + { + "id": 42, + "type": "IPAdapterApply", + "pos": [ + 658, + 2189 + ], + "size": { + "0": 315, + "1": 258 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "ipadapter", + "type": "IPADAPTER", + "link": 67, + "slot_index": 0 + }, + { + "name": "clip_vision", + "type": "CLIP_VISION", + "link": 68, + "slot_index": 1 + }, + { + "name": "image", + "type": "IMAGE", + "link": 139, + "slot_index": 2 + }, + { + "name": "model", + "type": "MODEL", + "link": 70 + }, + { + "name": "attn_mask", + "type": "MASK", + "link": null + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 71 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "IPAdapterApply" + }, + "widgets_values": [ + 0.9, + 0, + "linear", + 0, + 0.886, + false + ] } ], "links": [ @@ -1605,14 +1537,6 @@ 1, "CONTROL_NET" ], - [ - 23, - 6, - 2, - 17, - 1, - "VAE" - ], [ 25, 19, @@ -1621,54 +1545,6 @@ 3, "LATENT" ], - [ - 26, - 18, - 0, - 19, - 0, - "INT" - ], - [ - 27, - 18, - 1, - 19, - 1, - "INT" - ], - [ - 30, - 18, - 0, - 22, - 3, - "INT" - ], - [ - 31, - 18, - 1, - 22, - 4, - "INT" - ], - [ - 34, - 20, - 0, - 14, - 0, - "IMAGE" - ], - [ - 36, - 20, - 0, - 24, - 0, - "IMAGE" - ], [ 40, 26, @@ -1685,22 +1561,6 @@ 0, "CONDITIONING" ], - [ - 46, - 18, - 0, - 29, - 1, - "INT" - ], - [ - 47, - 18, - 1, - 29, - 2, - "INT" - ], [ 50, 32, @@ -1789,78 +1649,6 @@ 0, "MODEL" ], - [ - 74, - 45, - 0, - 22, - 0, - "IMAGE" - ], - [ - 75, - 45, - 1, - 22, - 1, - "MASK" - ], - [ - 76, - 45, - 0, - 2, - 0, - "IMAGE" - ], - [ - 77, - 45, - 0, - 17, - 0, - "IMAGE" - ], - [ - 78, - 45, - 0, - 18, - 0, - "IMAGE" - ], - [ - 79, - 45, - 0, - 26, - 0, - "IMAGE" - ], - [ - 80, - 45, - 1, - 25, - 0, - "MASK" - ], - [ - 82, - 45, - 2, - 29, - 0, - "IMAGE" - ], - [ - 83, - 45, - 2, - 42, - 2, - "IMAGE" - ], [ 85, 10, @@ -1869,14 +1657,6 @@ 0, "IMAGE" ], - [ - 87, - 45, - 0, - 50, - 0, - "IMAGE" - ], [ 95, 53, @@ -1885,14 +1665,6 @@ 0, "IMAGE" ], - [ - 97, - 18, - 1, - 53, - 1, - "INT" - ], [ 99, 52, @@ -1901,46 +1673,6 @@ 0, "MASK" ], - [ - 102, - 18, - 0, - 53, - 0, - "INT" - ], - [ - 103, - 22, - 0, - 20, - 0, - "LAYER" - ], - [ - 106, - 18, - 0, - 56, - 1, - "INT" - ], - [ - 107, - 18, - 1, - 56, - 2, - "INT" - ], - [ - 108, - 45, - 2, - 56, - 0, - "IMAGE" - ], [ 109, 56, @@ -1949,14 +1681,6 @@ 0, "IMAGE" ], - [ - 110, - 56, - 0, - 20, - 1, - "IMAGE" - ], [ 115, 60, @@ -1988,6 +1712,190 @@ 27, 1, "CONTROL_NET" + ], + [ + 120, + 61, + 0, + 19, + 0, + "INT" + ], + [ + 121, + 61, + 1, + 19, + 1, + "INT" + ], + [ + 122, + 61, + 0, + 22, + 3, + "INT" + ], + [ + 123, + 61, + 1, + 22, + 4, + "INT" + ], + [ + 124, + 61, + 0, + 29, + 1, + "INT" + ], + [ + 125, + 61, + 1, + 29, + 2, + "INT" + ], + [ + 126, + 61, + 0, + 53, + 0, + "INT" + ], + [ + 127, + 61, + 1, + 53, + 1, + "INT" + ], + [ + 128, + 61, + 0, + 56, + 1, + "INT" + ], + [ + 129, + 61, + 1, + 56, + 2, + "INT" + ], + [ + 131, + 63, + 0, + 64, + 0, + "IMAGE" + ], + [ + 132, + 63, + 0, + 22, + 0, + "IMAGE" + ], + [ + 133, + 63, + 0, + 61, + 0, + "IMAGE" + ], + [ + 134, + 63, + 0, + 26, + 0, + "IMAGE" + ], + [ + 135, + 63, + 1, + 22, + 1, + "MASK" + ], + [ + 136, + 63, + 1, + 25, + 0, + "MASK" + ], + [ + 137, + 63, + 2, + 29, + 0, + "IMAGE" + ], + [ + 138, + 63, + 2, + 56, + 0, + "IMAGE" + ], + [ + 139, + 63, + 2, + 42, + 2, + "IMAGE" + ], + [ + 140, + 22, + 0, + 65, + 0, + "LAYER" + ], + [ + 141, + 56, + 0, + 65, + 1, + "IMAGE" + ], + [ + 142, + 65, + 0, + 24, + 0, + "IMAGE" + ], + [ + 143, + 65, + 0, + 14, + 0, + "IMAGE" ] ], "groups": [], diff --git a/workflow/Text-to-Image-app.json b/workflow/Text-to-Image-app.json new file mode 100644 index 0000000..1bcdf95 --- /dev/null +++ b/workflow/Text-to-Image-app.json @@ -0,0 +1,717 @@ +{ + "last_node_id": 25, + "last_link_id": 32, + "nodes": [ + { + "id": 5, + "type": "CLIPTextEncode", + "pos": [ + 1029, + -2149 + ], + "size": { + "0": 425.27801513671875, + "1": 180.6060791015625 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 6 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 3 + ], + "slot_index": 0 + } + ], + "title": "负向prompt", + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "text, watermark" + ] + }, + { + "id": 6, + "type": "VAEDecode", + "pos": [ + 1867, + -2378 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": { + "collapsed": false + }, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 7 + }, + { + "name": "vae", + "type": "VAE", + "link": 8 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 9 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "VAEDecode" + } + }, + { + "id": 15, + "type": "EnhanceImage", + "pos": [ + 2591, + -2531 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 25 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 18 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "EnhanceImage" + }, + "widgets_values": [ + 1.1 + ] + }, + { + "id": 21, + "type": "EmptyLatentImage", + "pos": [ + 998, + -2674 + ], + "size": [ + 315, + 106 + ], + "flags": {}, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "width", + "type": "INT", + "link": 30, + "widget": { + "name": "width" + } + }, + { + "name": "height", + "type": "INT", + "link": 32, + "widget": { + "name": "height" + } + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 26 + ], + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "EmptyLatentImage" + }, + "widgets_values": [ + 512, + 512, + 1 + ] + }, + { + "id": 24, + "type": "LimitNumber", + "pos": [ + 665, + -2958 + ], + "size": { + "0": 315, + "1": 82 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "number", + "type": "*", + "link": 29 + } + ], + "outputs": [ + { + "name": "number", + "type": "*", + "links": [ + 30 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "LimitNumber" + }, + "widgets_values": [ + 512, + 4089 + ] + }, + { + "id": 25, + "type": "LimitNumber", + "pos": [ + 648, + -2659 + ], + "size": { + "0": 315, + "1": 82 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "number", + "type": "*", + "link": 31 + } + ], + "outputs": [ + { + "name": "number", + "type": "*", + "links": [ + 32 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "LimitNumber" + }, + "widgets_values": [ + 512, + 4089 + ] + }, + { + "id": 22, + "type": "IntNumber", + "pos": [ + 302, + -2758 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "INT", + "type": "INT", + "links": [ + 29 + ], + "shape": 3, + "slot_index": 0 + } + ], + "title": "Width", + "properties": { + "Node name for S&R": "IntNumber" + }, + "widgets_values": [ + 512 + ] + }, + { + "id": 23, + "type": "IntNumber", + "pos": [ + 299, + -2601 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "INT", + "type": "INT", + "links": [ + 31 + ], + "shape": 3, + "slot_index": 0 + } + ], + "title": "Height", + "properties": { + "Node name for S&R": "IntNumber" + }, + "widgets_values": [ + 512 + ] + }, + { + "id": 2, + "type": "CheckpointLoaderSimple", + "pos": [ + 567, + -2422 + ], + "size": { + "0": 315, + "1": 98 + }, + "flags": {}, + "order": 2, + "mode": 0, + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 1 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 5, + 6 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [ + 8 + ], + "slot_index": 2 + } + ], + "title": "Model", + "properties": { + "Node name for S&R": "CheckpointLoaderSimple" + }, + "widgets_values": [ + "deliberate_v2.safetensors" + ] + }, + { + "id": 1, + "type": "KSampler", + "pos": [ + 1509, + -2394 + ], + "size": { + "0": 315, + "1": 262 + }, + "flags": {}, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 1 + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 2 + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 3 + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 26, + "slot_index": 3 + }, + { + "name": "denoise", + "type": "FLOAT", + "link": 16, + "widget": { + "name": "denoise" + }, + "slot_index": 4 + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 7 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 730250870715434, + "randomize", + 15, + 6.9, + "euler", + "karras", + 0.59 + ] + }, + { + "id": 14, + "type": "FloatSlider", + "pos": [ + 1007, + -2819 + ], + "size": { + "0": 315, + "1": 58 + }, + "flags": {}, + "order": 3, + "mode": 0, + "outputs": [ + { + "name": "FLOAT", + "type": "FLOAT", + "links": [ + 16 + ], + "shape": 3, + "slot_index": 0 + } + ], + "title": "denoise", + "properties": { + "Node name for S&R": "FloatSlider" + }, + "widgets_values": [ + 1 + ] + }, + { + "id": 16, + "type": "PreviewImage", + "pos": [ + 2949, + -2615 + ], + "size": { + "0": 210, + "1": 246 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 18 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + } + }, + { + "id": 4, + "type": "CLIPTextEncode", + "pos": [ + 1022, + -2375 + ], + "size": { + "0": 422.84503173828125, + "1": 164.31304931640625 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 5 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 2 + ], + "slot_index": 0 + } + ], + "title": "prompt", + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "superman,fat cat" + ] + }, + { + "id": 7, + "type": "AppInfo", + "pos": [ + 2134, + -2528 + ], + "size": { + "0": 408.4201965332031, + "1": 406.9195861816406 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "image", + "type": "IMAGE", + "link": 9 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 25 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "AppInfo" + }, + "widgets_values": [ + "Text-to-Image", + "4\n22\n23\n2\n\n\n", + "16", + "演示基本的文生图流程", + 1, + "#comfyui-mixlab-nodes# ", + null + ] + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "MODEL" + ], + [ + 2, + 4, + 0, + 1, + 1, + "CONDITIONING" + ], + [ + 3, + 5, + 0, + 1, + 2, + "CONDITIONING" + ], + [ + 5, + 2, + 1, + 4, + 0, + "CLIP" + ], + [ + 6, + 2, + 1, + 5, + 0, + "CLIP" + ], + [ + 7, + 1, + 0, + 6, + 0, + "LATENT" + ], + [ + 8, + 2, + 2, + 6, + 1, + "VAE" + ], + [ + 9, + 6, + 0, + 7, + 0, + "IMAGE" + ], + [ + 16, + 14, + 0, + 1, + 4, + "FLOAT" + ], + [ + 18, + 15, + 0, + 16, + 0, + "IMAGE" + ], + [ + 25, + 7, + 0, + 15, + 0, + "IMAGE" + ], + [ + 26, + 21, + 0, + 1, + 3, + "LATENT" + ], + [ + 29, + 22, + 0, + 24, + 0, + "*" + ], + [ + 30, + 24, + 0, + 21, + 0, + "INT" + ], + [ + 31, + 23, + 0, + 25, + 0, + "*" + ], + [ + 32, + 25, + 0, + 21, + 1, + "INT" + ] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file diff --git a/workflow/appinfo-workflow.svg b/workflow/appinfo-workflow.svg index 126b809..f28f21d 100644 --- a/workflow/appinfo-workflow.svg +++ b/workflow/appinfo-workflow.svg @@ -1 +1 @@ -T: 0.00sI: 0N: 10 [10]V: 20FPS:312.50VAE Decode#6 samplesvaeIMAGELoad Image#11 IMAGEMASKimage1703572811473.pngchoose file to uploadLoad Checkpoint#2 MODELCLIPVAEckpt_namedeliberate_v2.safetensorsVAE Encode#12 pixelsvaeLATENT负向prompt#5 clipCONDITIONINGtext, watermark 正向prompt#4 clipCONDITIONINGblue hair Save Image#8 imagesfilename_prefiximage-to-imageKSampler#1 modelpositivenegativelatent_imagedenoiseLATENTseed906540972228779control_after_generaterandomizesteps20cfg8.0sampler_nameeulerschedulernormalFloatSlider#14 FLOATnumber 0.45AppInfo ♾️Mixlab#7 imageIMAGEnameimage-to-image 11 4 14 8 最基本的工作流演示 version1{"last_node_id":14,"last_link_id":16,"nodes":[{"id":6,"type":"VAEDecode","pos":[1885,-2361],"size":{"0":210,"1":46},"flags":{"collapsed":false},"order":7,"mode":0,"inputs":[{"name":"samples","type":"LATENT","link":7},{"name":"vae","type":"VAE","link":8}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[9],"slot_index":0}],"properties":{"Node name for S&R":"VAEDecode"}},{"id":11,"type":"LoadImage","pos":[583,-2681],"size":{"0":315,"1":314},"flags":{},"order":0,"mode":0,"outputs":[{"name":"IMAGE","type":"IMAGE","links":[12],"shape":3,"slot_index":0},{"name":"MASK","type":"MASK","links":null,"shape":3}],"properties":{"Node name for S&R":"LoadImage"},"widgets_values":["1703572811473.png","image"]},{"id":2,"type":"CheckpointLoaderSimple","pos":[606.7134002168859,-2074.502640857575],"size":{"0":315,"1":98},"flags":{},"order":1,"mode":0,"outputs":[{"name":"MODEL","type":"MODEL","links":[1],"slot_index":0},{"name":"CLIP","type":"CLIP","links":[5,6],"slot_index":1},{"name":"VAE","type":"VAE","links":[8,13],"slot_index":2}],"properties":{"Node name for S&R":"CheckpointLoaderSimple"},"widgets_values":["deliberate_v2.safetensors"]},{"id":12,"type":"VAEEncode","pos":[1016.6295835601803,-2655.91833999939],"size":{"0":210,"1":46},"flags":{},"order":5,"mode":0,"inputs":[{"name":"pixels","type":"IMAGE","link":12},{"name":"vae","type":"VAE","link":13}],"outputs":[{"name":"LATENT","type":"LATENT","links":[14],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"VAEEncode"}},{"id":5,"type":"CLIPTextEncode","pos":[1029,-2149],"size":{"0":425.27801513671875,"1":180.6060791015625},"flags":{},"order":4,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":6}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[3],"slot_index":0}],"title":"负向prompt","properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["text, watermark"]},{"id":4,"type":"CLIPTextEncode","pos":[1022,-2376],"size":{"0":422.84503173828125,"1":164.31304931640625},"flags":{},"order":3,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":5}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[2],"slot_index":0}],"title":"正向prompt","properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["blue hair"]},{"id":8,"type":"SaveImage","pos":[2596,-2428],"size":{"0":315,"1":270},"flags":{},"order":9,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":11}],"properties":{},"widgets_values":["image-to-image"]},{"id":1,"type":"KSampler","pos":[1509,-2394],"size":{"0":315,"1":262},"flags":{},"order":6,"mode":0,"inputs":[{"name":"model","type":"MODEL","link":1},{"name":"positive","type":"CONDITIONING","link":2},{"name":"negative","type":"CONDITIONING","link":3},{"name":"latent_image","type":"LATENT","link":14},{"name":"denoise","type":"FLOAT","link":16,"widget":{"name":"denoise"},"slot_index":4}],"outputs":[{"name":"LATENT","type":"LATENT","links":[7],"slot_index":0}],"properties":{"Node name for S&R":"KSampler"},"widgets_values":[906540972228779,"randomize",20,8,"euler","normal",0.59]},{"id":14,"type":"FloatSlider","pos":[1500,-2554],"size":{"0":315,"1":58},"flags":{},"order":2,"mode":0,"outputs":[{"name":"FLOAT","type":"FLOAT","links":[16],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"FloatSlider"},"widgets_values":[0.45]},{"id":7,"type":"AppInfo","pos":[2147,-2394],"size":{"0":404.71221923828125,"1":299.52880859375},"flags":{},"order":8,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":9}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[11],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"AppInfo"},"widgets_values":["image-to-image","\n11\n4\n14","8","最基本的工作流演示",1,null]}],"links":[[1,2,0,1,0,"MODEL"],[2,4,0,1,1,"CONDITIONING"],[3,5,0,1,2,"CONDITIONING"],[5,2,1,4,0,"CLIP"],[6,2,1,5,0,"CLIP"],[7,1,0,6,0,"LATENT"],[8,2,2,6,1,"VAE"],[9,6,0,7,0,"IMAGE"],[11,7,0,8,0,"IMAGE"],[12,11,0,12,0,"IMAGE"],[13,2,2,12,1,"VAE"],[14,12,0,1,3,"LATENT"],[16,14,0,1,4,"FLOAT"]],"groups":[],"config":{},"extra":{},"version":0.4} \ No newline at end of file +T: 0.00sI: 0N: 11 [5]V: 22FPS:270.27负向prompt#5 clipCONDITIONINGtext, watermark KSampler#1 modelpositivenegativelatent_imagedenoiseLATENTseed492527429004648control_after_generaterandomizesteps20cfg8.0sampler_nameeulerschedulernormalVAE Decode#6 samplesvaeIMAGEVAE Encode#12 pixelsvaeLATENTLoad Checkpoint#2 MODELCLIPVAEckpt_namedeliberate_v2.safetensorsupload image#11 IMAGEMASKimage1703572811473.pngchoose file to uploaddenoise#14 FLOATnumber 0.450EnhanceImage#15 imageIMAGEcontrast 1.10Preview Image#16 imagesAppInfo ♾️Mixlab#7 imageIMAGEnameImage-to-Image11 14 4 2 16 演示基本的图生图流程 version2share_prefix#comfyui-mixlab-nodes# 正向prompt#4 clipCONDITIONINGhair,girl {"last_node_id":20,"last_link_id":25,"nodes":[{"id":5,"type":"CLIPTextEncode","pos":[1029,-2149],"size":{"0":425.27801513671875,"1":180.6060791015625},"flags":{},"order":4,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":6}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[3],"slot_index":0}],"title":"负向prompt","properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["text, watermark"]},{"id":1,"type":"KSampler","pos":[1509,-2394],"size":{"0":315,"1":262},"flags":{},"order":6,"mode":0,"inputs":[{"name":"model","type":"MODEL","link":1},{"name":"positive","type":"CONDITIONING","link":2},{"name":"negative","type":"CONDITIONING","link":3},{"name":"latent_image","type":"LATENT","link":14},{"name":"denoise","type":"FLOAT","link":16,"widget":{"name":"denoise"},"slot_index":4}],"outputs":[{"name":"LATENT","type":"LATENT","links":[7],"slot_index":0}],"properties":{"Node name for S&R":"KSampler"},"widgets_values":[492527429004648,"randomize",20,8,"euler","normal",0.59]},{"id":6,"type":"VAEDecode","pos":[1867,-2378],"size":{"0":210,"1":46},"flags":{"collapsed":false},"order":7,"mode":0,"inputs":[{"name":"samples","type":"LATENT","link":7},{"name":"vae","type":"VAE","link":8}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[9],"slot_index":0}],"properties":{"Node name for S&R":"VAEDecode"}},{"id":12,"type":"VAEEncode","pos":[1031,-2482],"size":{"0":210,"1":46},"flags":{},"order":5,"mode":0,"inputs":[{"name":"pixels","type":"IMAGE","link":12},{"name":"vae","type":"VAE","link":13}],"outputs":[{"name":"LATENT","type":"LATENT","links":[14],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"VAEEncode"}},{"id":2,"type":"CheckpointLoaderSimple","pos":[613,-2395],"size":{"0":315,"1":98},"flags":{},"order":0,"mode":0,"outputs":[{"name":"MODEL","type":"MODEL","links":[1],"slot_index":0},{"name":"CLIP","type":"CLIP","links":[5,6],"slot_index":1},{"name":"VAE","type":"VAE","links":[8,13],"slot_index":2}],"properties":{"Node name for S&R":"CheckpointLoaderSimple"},"widgets_values":["deliberate_v2.safetensors"]},{"id":11,"type":"LoadImage","pos":[626,-2823],"size":{"0":315,"1":314},"flags":{},"order":1,"mode":0,"outputs":[{"name":"IMAGE","type":"IMAGE","links":[12],"shape":3,"slot_index":0},{"name":"MASK","type":"MASK","links":null,"shape":3}],"title":"upload image","properties":{"Node name for S&R":"LoadImage"},"widgets_values":["1703572811473.png","image"]},{"id":14,"type":"FloatSlider","pos":[1007,-2819],"size":{"0":315,"1":58},"flags":{},"order":2,"mode":0,"outputs":[{"name":"FLOAT","type":"FLOAT","links":[16],"shape":3,"slot_index":0}],"title":"denoise","properties":{"Node name for S&R":"FloatSlider"},"widgets_values":[0.45]},{"id":15,"type":"EnhanceImage","pos":[2591,-2531],"size":{"0":315,"1":58},"flags":{},"order":9,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":25}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[18],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"EnhanceImage"},"widgets_values":[1.1]},{"id":16,"type":"PreviewImage","pos":[2963,-2520],"size":{"0":210,"1":246},"flags":{},"order":10,"mode":0,"inputs":[{"name":"images","type":"IMAGE","link":18}],"properties":{"Node name for S&R":"PreviewImage"}},{"id":7,"type":"AppInfo","pos":[2134,-2528],"size":{"0":408.4201965332031,"1":406.9195861816406},"flags":{},"order":8,"mode":0,"inputs":[{"name":"image","type":"IMAGE","link":9}],"outputs":[{"name":"IMAGE","type":"IMAGE","links":[25],"shape":3,"slot_index":0}],"properties":{"Node name for S&R":"AppInfo"},"widgets_values":["Image-to-Image","11\n14\n4\n2\n","16","演示基本的图生图流程",2,"#comfyui-mixlab-nodes# ",null]},{"id":4,"type":"CLIPTextEncode","pos":[1022,-2375],"size":{"0":422.84503173828125,"1":164.31304931640625},"flags":{},"order":3,"mode":0,"inputs":[{"name":"clip","type":"CLIP","link":5}],"outputs":[{"name":"CONDITIONING","type":"CONDITIONING","links":[2],"slot_index":0}],"title":"正向prompt","properties":{"Node name for S&R":"CLIPTextEncode"},"widgets_values":["hair,girl"]}],"links":[[1,2,0,1,0,"MODEL"],[2,4,0,1,1,"CONDITIONING"],[3,5,0,1,2,"CONDITIONING"],[5,2,1,4,0,"CLIP"],[6,2,1,5,0,"CLIP"],[7,1,0,6,0,"LATENT"],[8,2,2,6,1,"VAE"],[9,6,0,7,0,"IMAGE"],[12,11,0,12,0,"IMAGE"],[13,2,2,12,1,"VAE"],[14,12,0,1,3,"LATENT"],[16,14,0,1,4,"FLOAT"],[18,15,0,16,0,"IMAGE"],[25,7,0,15,0,"IMAGE"]],"groups":[],"config":{},"extra":{},"version":0.4} \ No newline at end of file