Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe57286959 | ||
|
|
03645bbb33 | ||
|
|
93dba9a399 | ||
|
|
5627ea8073 | ||
|
|
7ba679c9ce | ||
|
|
c7a450e6ce | ||
|
|
beda5156bf | ||
|
|
76a9da7163 |
@@ -53,6 +53,7 @@
|
||||
- web app 可以设置分类,在 comfyui 右键菜单可以编辑更新 web app
|
||||
- 支持动态提示
|
||||
- 支持把输出显示到comfyui背景(TouchDesigner 风格)
|
||||
- 如果转为web app打开是空白的,注意检查下插件目录的名字需要是:comfyui-mixlab-nodes(如果是zip包下载会多了个-main的后缀,需要去掉)
|
||||
|
||||

|
||||
|
||||
|
||||
+42
-39
@@ -22,9 +22,8 @@ except:
|
||||
print('#fix sys.stdout.isatty')
|
||||
sys.stdout.isatty = lambda: False
|
||||
|
||||
llama_port=None
|
||||
llama_model=""
|
||||
llama_chat_format=""
|
||||
_URL_=None
|
||||
|
||||
|
||||
# try:
|
||||
# from .nodes.ChatGPT import get_llama_models,get_llama_model_path,llama_cpp_client
|
||||
@@ -320,22 +319,22 @@ def get_my_workflow_for_app(filename="my_workflow_app.json",category="",is_all=F
|
||||
|
||||
# 这个代码不需要
|
||||
# if len(apps)==1 and category!='' and category!=None:
|
||||
data=read_workflow_json_files(category_path)
|
||||
data=read_workflow_json_files(category_path)
|
||||
|
||||
for item in data:
|
||||
x=item["data"]
|
||||
# print(apps[0]['filename'] ,item["filename"])
|
||||
if apps[0]['filename']!=item["filename"]:
|
||||
category=''
|
||||
input=None
|
||||
output=None
|
||||
if 'category' in x['app']:
|
||||
category=x['app']['category']
|
||||
if 'input' in x['app']:
|
||||
input=x['app']['input']
|
||||
if 'output' in x['app']:
|
||||
output=x['app']['output']
|
||||
apps.append({
|
||||
for item in data:
|
||||
x=item["data"]
|
||||
# print(apps[0]['filename'] ,item["filename"])
|
||||
if apps[0]['filename']!=item["filename"]:
|
||||
category=''
|
||||
input=None
|
||||
output=None
|
||||
if 'category' in x['app']:
|
||||
category=x['app']['category']
|
||||
if 'input' in x['app']:
|
||||
input=x['app']['input']
|
||||
if 'output' in x['app']:
|
||||
output=x['app']['output']
|
||||
apps.append({
|
||||
"filename":item["filename"],
|
||||
# "category":category,
|
||||
"data":{
|
||||
@@ -455,6 +454,7 @@ async def check_port_available(address, port):
|
||||
|
||||
# https
|
||||
async def new_start(self, address, port, verbose=True, call_on_start=None):
|
||||
global _URL_
|
||||
try:
|
||||
runner = web.AppRunner(self.app, access_log=None)
|
||||
await runner.setup()
|
||||
@@ -534,7 +534,8 @@ async def new_start(self, address, port, verbose=True, call_on_start=None):
|
||||
# print("\033[93mStarting server\n")
|
||||
logging.info("\033[93mTo see the GUI go to: http://{}:{} or http://{}:{}".format(ip_address, http_port,address,http_port))
|
||||
logging.info("\033[93mTo see the GUI go to: https://{}:{} or https://{}:{}\033[0m".format(ip_address, https_port,address,https_port))
|
||||
|
||||
|
||||
_URL_="http://{}:{}".format(address,http_port)
|
||||
# print("\033[93mTo see the GUI go to: http://{}:{}".format(address, http_port))
|
||||
# print("\033[93mTo see the GUI go to: https://{}:{}\033[0m".format(address, https_port))
|
||||
|
||||
@@ -754,15 +755,16 @@ def random_seed(seed, data):
|
||||
|
||||
for id, value in data.items():
|
||||
# print(seed,id)
|
||||
if 'seed' in value['inputs'] and not isinstance(value['inputs']['seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['seed'] = round(random.random() * max_seed)
|
||||
|
||||
if 'noise_seed' in value['inputs'] and not isinstance(value['inputs']['noise_seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['noise_seed'] = round(random.random() * max_seed)
|
||||
|
||||
if value.get('class_type') == "Seed_" and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['seed'] = round(random.random() * max_seed)
|
||||
|
||||
if id in seed:
|
||||
if 'seed' in value['inputs'] and not isinstance(value['inputs']['seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['seed'] = round(random.random() * max_seed)
|
||||
|
||||
if 'noise_seed' in value['inputs'] and not isinstance(value['inputs']['noise_seed'], list) and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['noise_seed'] = round(random.random() * max_seed)
|
||||
|
||||
if value.get('class_type') == "Seed_" and seed[id] in ['increment', 'decrement', 'randomize']:
|
||||
value['inputs']['seed'] = round(random.random() * max_seed)
|
||||
|
||||
print('new Seed', value)
|
||||
|
||||
return data
|
||||
@@ -992,16 +994,19 @@ def re_start(request):
|
||||
pass
|
||||
return os.execv(sys.executable, [sys.executable] + sys.argv)
|
||||
|
||||
|
||||
# 状态
|
||||
@routes.get('/mixlab/status')
|
||||
def mix_status(request):
|
||||
return web.Response(text="running#"+_URL_)
|
||||
|
||||
# 导入节点
|
||||
from .nodes.PromptNode import GLIGENTextBoxApply_Advanced,EmbeddingPrompt,RandomPrompt,PromptSlide,PromptSimplification,PromptImage,JoinWithDelimiter
|
||||
from .nodes.ImageNode import ImageListToBatch_,ComparingTwoFrames,LoadImages_,CompositeImages,GridDisplayAndSave,GridInput,ImagesPrompt,SaveImageAndMetadata,SaveImageToLocal,SplitImage,GridOutput,GetImageSize_,MirroredImage,ImageColorTransfer,NoiseImage,TransparentImage,GradientImage,LoadImagesFromPath,LoadImagesFromURL,ResizeImage,TextImage,SvgImage,Image3D,ShowLayer,NewLayer,MergeLayers,CenterImage,AreaToMask,SmoothMask,SplitLongMask,ImageCropByAlpha,EnhanceImage,FaceToMask
|
||||
from .nodes.ImageNode import ImageBatchToList_,ImageListToBatch_,ComparingTwoFrames,LoadImages_,CompositeImages,GridDisplayAndSave,GridInput,ImagesPrompt,SaveImageAndMetadata,SaveImageToLocal,SplitImage,GridOutput,GetImageSize_,MirroredImage,ImageColorTransfer,NoiseImage,TransparentImage,GradientImage,LoadImagesFromPath,LoadImagesFromURL,ResizeImage,TextImage,SvgImage,Image3D,ShowLayer,NewLayer,MergeLayers,CenterImage,AreaToMask,SmoothMask,SplitLongMask,ImageCropByAlpha,EnhanceImage,FaceToMask
|
||||
# from .nodes.Vae import VAELoader,VAEDecode
|
||||
from .nodes.ScreenShareNode import ScreenShareNode,FloatingVideo
|
||||
|
||||
from .nodes.Audio import AudioPlayNode,SpeechRecognition,SpeechSynthesis
|
||||
from .nodes.Utils import IncrementingListNode,ListSplit,CreateLoraNames,CreateSampler_names,CreateCkptNames,CreateSeedNode,TESTNODE_,TESTNODE_TOKEN,AppInfo,IntNumber,FloatSlider,TextInput,ColorInput,FontInput,TextToNumber,DynamicDelayProcessor,LimitNumber,SwitchByIndex,MultiplicationNode
|
||||
from .nodes.Utils import KeyInput,IncrementingListNode,ListSplit,CreateLoraNames,CreateSampler_names,CreateCkptNames,CreateSeedNode,TESTNODE_,TESTNODE_TOKEN,AppInfo,IntNumber,FloatSlider,TextInput,ColorInput,FontInput,TextToNumber,DynamicDelayProcessor,LimitNumber,SwitchByIndex,MultiplicationNode
|
||||
from .nodes.Mask import PreviewMask_,MaskListReplace,MaskListMerge,OutlineMask,FeatheredMask
|
||||
|
||||
from .nodes.Style import ApplyVisualStylePrompting,StyleAlignedReferenceSampler,StyleAlignedBatchAlign,StyleAlignedSampleReferenceLatents
|
||||
@@ -1037,6 +1042,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"ShowLayer":ShowLayer,
|
||||
"NewLayer":NewLayer,
|
||||
"ImageListToBatch_":ImageListToBatch_,
|
||||
"ImageBatchToList_":ImageBatchToList_,
|
||||
"CompositeImages_":CompositeImages,
|
||||
"SplitImage":SplitImage,
|
||||
"CenterImage":CenterImage,
|
||||
@@ -1061,6 +1067,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
|
||||
"SpeechRecognition":SpeechRecognition,
|
||||
"SpeechSynthesis":SpeechSynthesis,
|
||||
"KeyInput":KeyInput,
|
||||
"Color":ColorInput,
|
||||
"FloatSlider":FloatSlider,
|
||||
"IntNumber":IntNumber,
|
||||
@@ -1117,6 +1124,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"SpeechRecognition":"SpeechRecognition ♾️Mixlab",
|
||||
"3DImage":"3DImage ♾️Mixlab",
|
||||
"ImageListToBatch_":"Image List To Batch",
|
||||
"ImageBatchToList_":"Image Batch To List",
|
||||
"CompositeImages_":"Composite Images ♾️Mixlab",
|
||||
"DynamicDelayProcessor":"DynamicDelayByText ♾️Mixlab",
|
||||
"LaMaInpainting":"LaMaInpainting ♾️Mixlab",
|
||||
@@ -1153,7 +1161,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
# web ui的节点功能
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
|
||||
logging.info('--------------')
|
||||
logging.info('\033[91m ### Mixlab Nodes: \033[93mLoaded')
|
||||
# print('\033[91m ### Mixlab Nodes: \033[93mLoaded')
|
||||
@@ -1162,7 +1169,7 @@ try:
|
||||
from .nodes.ChatGPT import ChatGPTNode,ShowTextForGPT,CharacterInText,TextSplitByDelimiter,SiliconflowFreeNode
|
||||
logging.info('ChatGPT.available True')
|
||||
|
||||
NODE_CLASS_MAPPINGS_V = {
|
||||
NODE_CLASS_MAPPINGS_V = {
|
||||
"ChatGPTOpenAI":ChatGPTNode,
|
||||
"SiliconflowLLM":SiliconflowFreeNode,
|
||||
"ShowTextForGPT":ShowTextForGPT,
|
||||
@@ -1171,7 +1178,7 @@ try:
|
||||
}
|
||||
|
||||
# 一个包含节点友好/可读的标题的字典
|
||||
NODE_DISPLAY_NAME_MAPPINGS_V = {
|
||||
NODE_DISPLAY_NAME_MAPPINGS_V = {
|
||||
"ChatGPTOpenAI":"ChatGPT & Local LLM ♾️Mixlab",
|
||||
"SiliconflowLLM":"LLM Siliconflow ♾️Mixlab",
|
||||
"ShowTextForGPT":"Show Text ♾️MixlabApp",
|
||||
@@ -1268,7 +1275,7 @@ except:
|
||||
try:
|
||||
from .nodes.TripoSR import LoadTripoSRModel,TripoSRSampler,SaveTripoSRMesh
|
||||
logging.info('TripoSR.available')
|
||||
|
||||
# logging.info( folder_paths.get_temp_directory())
|
||||
NODE_CLASS_MAPPINGS['LoadTripoSRModel_']=LoadTripoSRModel
|
||||
NODE_DISPLAY_NAME_MAPPINGS["LoadTripoSRModel_"]= "Load TripoSR Model"
|
||||
|
||||
@@ -1283,8 +1290,4 @@ except Exception as e:
|
||||
logging.info('TripoSR.available False' )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
logging.info('\033[93m -------------- \033[0m')
|
||||
|
||||
@@ -1829,12 +1829,9 @@ class CompositeImages:
|
||||
|
||||
def run(self, foreground,mask,background, is_multiply_blend, position, scale):
|
||||
results = []
|
||||
|
||||
f1=[]
|
||||
for fg, mask in zip(foreground, mask ):
|
||||
f1.append([fg,mask])
|
||||
|
||||
|
||||
for f, bg in product(f1, background):
|
||||
[fg,mask]=f
|
||||
fg_pil = tensor2pil(fg)
|
||||
|
||||
@@ -181,6 +181,28 @@ class ColorInput:
|
||||
return (h,r,g,b,a,)
|
||||
|
||||
|
||||
class KeyInput:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {"required": {
|
||||
"key":("KEY",),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("key",)
|
||||
|
||||
FUNCTION = "run"
|
||||
|
||||
CATEGORY = "♾️Mixlab/Input"
|
||||
|
||||
INPUT_IS_LIST = False
|
||||
OUTPUT_IS_LIST = (False,)
|
||||
|
||||
def run(self,key):
|
||||
return (key,)
|
||||
|
||||
|
||||
|
||||
class FontInput:
|
||||
@classmethod
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
[project]
|
||||
name = "comfyui-mixlab-nodes"
|
||||
description = "3D, ScreenShareNode & FloatingVideoNode, SpeechRecognition & SpeechSynthesis, GPT, LoadImagesFromLocal, Layers, Other Nodes, ..."
|
||||
version = "0.33.0"
|
||||
license = "MIT"
|
||||
version = "0.34.0"
|
||||
license = { text = "MIT License" }
|
||||
dependencies = ["numpy", "pyOpenSSL", "watchdog", "opencv-python-headless", "matplotlib", "openai", "simple-lama-inpainting", "clip-interrogator==0.6.0", "transformers>=4.36.0", "lark-parser", "imageio-ffmpeg", "rembg[gpu]", "omegaconf==2.3.0", "Pillow>=9.5.0", "einops==0.7.0", "trimesh>=4.0.5", "huggingface-hub", "scikit-image"]
|
||||
|
||||
[project.urls]
|
||||
|
||||
+14
-4
@@ -1740,7 +1740,7 @@
|
||||
if (data.class_type === 'CheckpointLoaderSimple') {
|
||||
if (window._appData.data) window._appData.data[data.id].inputs.ckpt_name = selectDom.value;
|
||||
//更新输入参数
|
||||
updateInputData(nodeId, (inputs) => {
|
||||
updateInputData(data.id, (inputs) => {
|
||||
inputs.ckpt_name = selectDom.value;
|
||||
return inputs
|
||||
})
|
||||
@@ -1748,7 +1748,7 @@
|
||||
if (data.class_type === 'LoraLoader') {
|
||||
if (window._appData.data) window._appData.data[data.id].inputs.lora_name = selectDom.value;
|
||||
//更新输入参数
|
||||
updateInputData(nodeId, (inputs) => {
|
||||
updateInputData(data.id, (inputs) => {
|
||||
inputs.lora_name = selectDom.value;
|
||||
return inputs
|
||||
})
|
||||
@@ -2870,7 +2870,12 @@
|
||||
window._appData.category,
|
||||
window._appData.seed,
|
||||
inp,
|
||||
api.clientId
|
||||
api.clientId,
|
||||
window._appData.data ? [{
|
||||
data: {
|
||||
output: window._appData.data
|
||||
}
|
||||
}] : null
|
||||
).then(res => {
|
||||
|
||||
if (!res) {
|
||||
@@ -2900,7 +2905,12 @@
|
||||
window._appData.category,
|
||||
window._appData.seed,
|
||||
window._appData.input.filter(inp => inp),
|
||||
api.clientId
|
||||
api.clientId,
|
||||
window._appData.data ? [{
|
||||
data: {
|
||||
output: window._appData.data
|
||||
}
|
||||
}] : null
|
||||
).then(res => {
|
||||
|
||||
if (!res) {
|
||||
|
||||
@@ -3,7 +3,8 @@ import { $el } from '../../../scripts/ui.js'
|
||||
import { api } from '../../../scripts/api.js'
|
||||
|
||||
import { td_bg } from './td_background.js'
|
||||
console.log('td_bg', td_bg)
|
||||
// console.log('td_bg', td_bg)
|
||||
|
||||
//本机安装的插件节点全集
|
||||
window._nodesAll = null
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { app } from '../../../scripts/app.js'
|
||||
const repoOwner = 'shadowcz007' // 替换为仓库的所有者
|
||||
const repoName = 'comfyui-mixlab-nodes' // 替换为仓库的名称
|
||||
|
||||
const version = 'v0.33.0'
|
||||
const version = 'v0.34.0'
|
||||
|
||||
fetch(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`)
|
||||
.then(response => response.json())
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
function get_url () {
|
||||
// 如果有缓存记录
|
||||
let hostUrl = localStorage.getItem('_hostUrl') || ''
|
||||
if (hostUrl) {
|
||||
return hostUrl
|
||||
}
|
||||
let api_host = `${window.location.hostname}:${window.location.port}`
|
||||
let api_base = ''
|
||||
let url = `${window.location.protocol}//${api_host}${api_base}`
|
||||
@@ -137,14 +142,18 @@ async function getPromptResult (category) {
|
||||
}
|
||||
|
||||
// 新的运行工作流的接口
|
||||
function queuePromptNew (filename, category, seed, input, client_id) {
|
||||
function queuePromptNew (filename, category, seed, input, client_id,apps=null) {
|
||||
let url = get_url()
|
||||
// var filename = "Text-to-Image_1.json", category = "";
|
||||
|
||||
// 随机seed
|
||||
// promptWorkflow = randomSeed(seed, promptWorkflow);
|
||||
let d = { filename, category, seed, input, client_id }
|
||||
if (apps) {
|
||||
d.apps = apps
|
||||
}
|
||||
|
||||
const data = JSON.stringify({ filename, category, seed, input, client_id })
|
||||
const data = JSON.stringify(d)
|
||||
return new Promise((res, rej) => {
|
||||
fetch(`${url}/mixlab/prompt`, {
|
||||
method: 'POST',
|
||||
|
||||
@@ -675,6 +675,17 @@ const createInputImageForBatch = (base64, widget) => {
|
||||
return im
|
||||
}
|
||||
|
||||
// 添加新图片
|
||||
const addBase64ToWidgetForLoadImagesToBatch = (
|
||||
base64,
|
||||
imagesWidget,
|
||||
imagesDiv
|
||||
) => {
|
||||
imagesWidget.value.base64.push(base64)
|
||||
let im = createInputImageForBatch(base64, imagesWidget)
|
||||
imagesDiv.appendChild(im)
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.Comfy.LoadImagesToBatch',
|
||||
async getCustomWidgets (app) {
|
||||
@@ -705,7 +716,6 @@ app.registerExtension({
|
||||
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'LoadImagesToBatch') {
|
||||
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
@@ -751,13 +761,18 @@ app.registerExtension({
|
||||
base64 = await loadImageToCanvas(base64)
|
||||
// console.log(base64)
|
||||
if (!imagesWidget.value) imagesWidget.value = { base64: [] }
|
||||
imagesWidget.value.base64.push(base64)
|
||||
let im = createInputImageForBatch(base64, imagesWidget)
|
||||
imagesDiv.appendChild(im)
|
||||
addBase64ToWidgetForLoadImagesToBatch(
|
||||
base64,
|
||||
imagesWidget,
|
||||
imagesDiv
|
||||
)
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
|
||||
// 如果是复制的,有数据 , 这个不生效,取不到数据, 需要在nodeCreated里获取
|
||||
// console.log('#LoadImagesToBatch', imagesWidget.value?.base64)
|
||||
|
||||
const btn = document.createElement('button')
|
||||
btn.innerText = 'Upload Image'
|
||||
|
||||
@@ -829,18 +844,36 @@ app.registerExtension({
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async loadedGraphNode (node, app) {
|
||||
if (node.type === 'LoadImagesToBatch') {
|
||||
// await sleep(0)
|
||||
let imagesWidget = node.widgets.filter(w => w.name === 'images')[0]
|
||||
let imagePreview = node.widgets.filter(w => w.name == 'image_base64')[0]
|
||||
// console.log('#LoadImagesToBatch', imagesWidget.value?.base64)
|
||||
let imagesDiv = imagePreview.div.querySelector('.images_preview')
|
||||
|
||||
let pre = imagePreview.div.querySelector('.images_preview')
|
||||
for (const d of imagesWidget.value?.base64 || []) {
|
||||
let im = createInputImageForBatch(d, imagesWidget)
|
||||
pre.appendChild(im)
|
||||
imagesDiv.appendChild(im)
|
||||
}
|
||||
}
|
||||
},
|
||||
nodeCreated (node, app) {
|
||||
//数据延迟??
|
||||
setTimeout(() => {
|
||||
console.log('#LoadImagesToBatch', node.type)
|
||||
if (node.type === 'LoadImagesToBatch') {
|
||||
let imagesWidget = node.widgets.filter(w => w.name === 'images')[0]
|
||||
let imagePreview = node.widgets.filter(w => w.name == 'image_base64')[0]
|
||||
|
||||
let imagesDiv = imagePreview?.div?.querySelector('.images_preview')
|
||||
|
||||
for (const d of imagesWidget.value?.base64 || []) {
|
||||
let im = createInputImageForBatch(d, imagesWidget)
|
||||
imagesDiv.appendChild(im)
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -868,8 +901,8 @@ app.registerExtension({
|
||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
const r = onNodeCreated
|
||||
? onNodeCreated.apply(this, arguments)
|
||||
: undefined
|
||||
? onNodeCreated.apply(this, arguments)
|
||||
: undefined
|
||||
|
||||
this.size = [400, this.size[1]]
|
||||
console.log('##onNodeCreated', this)
|
||||
@@ -891,20 +924,15 @@ app.registerExtension({
|
||||
this.addCustomWidget(widget)
|
||||
this.serialize_widgets = true //需要保存参数
|
||||
|
||||
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = () => {
|
||||
widget.div.remove()
|
||||
return onRemoved?.()
|
||||
}
|
||||
|
||||
|
||||
return r
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
@@ -964,7 +992,7 @@ app.registerExtension({
|
||||
label: 'After'
|
||||
}
|
||||
]
|
||||
this.size=[this.size[0],300]
|
||||
this.size = [this.size[0], 300]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -974,7 +1002,6 @@ app.registerExtension({
|
||||
// node.widgets[0].div.id = 'mix_comparingtowframes_' + node.id
|
||||
// if (node.widgets_values && node.widgets_values[0]) {
|
||||
// node.widgets[0].div.innerHTML = ''
|
||||
|
||||
// let slider = new juxtapose.JXSlider(
|
||||
// '#mix_comparingtowframes_' + node.id,
|
||||
// node.widgets_values,
|
||||
|
||||
+126
-26
@@ -1,5 +1,5 @@
|
||||
import { app } from '../../../scripts/app.js'
|
||||
import { $el } from '../../../scripts/ui.js'
|
||||
import { $el } from '../../../scripts/ui.js'
|
||||
|
||||
const getLocalData = key => {
|
||||
let data = {}
|
||||
@@ -122,7 +122,7 @@ app.registerExtension({
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
|
||||
// console.log('Color nodeData', this.widgets)
|
||||
console.log('Color nodeData', this.div)
|
||||
|
||||
const widget = {
|
||||
type: 'div',
|
||||
@@ -273,19 +273,19 @@ app.registerExtension({
|
||||
})
|
||||
|
||||
const min_max = node => {
|
||||
if(node.widgets){
|
||||
if (node.widgets) {
|
||||
const min_value = node.widgets.filter(w => w.name === 'min_value')[0]
|
||||
const max_value = node.widgets.filter(w => w.name === 'max_value')[0]
|
||||
|
||||
|
||||
const number = node.widgets.filter(w => w.name === 'number')[0]
|
||||
if (number) {
|
||||
number.options.min = min_value.value
|
||||
number.options.max = max_value.value
|
||||
|
||||
|
||||
number.value = Math.min(number.options.max, number.value)
|
||||
number.value = Math.max(number.options.min, number.value)
|
||||
}
|
||||
|
||||
|
||||
if (min_value)
|
||||
min_value.callback = e => {
|
||||
number.options.min = e
|
||||
@@ -297,22 +297,18 @@ const min_max = node => {
|
||||
number.value = e
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.FloatSlider',
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
|
||||
if (nodeType.comfyClass == 'FloatSlider') {
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated;
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
min_max(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
if (node.type === 'FloatSlider') {
|
||||
@@ -323,7 +319,6 @@ app.registerExtension({
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.IntNumber',
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
|
||||
if (nodeType.comfyClass == 'IntNumber') {
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
@@ -331,7 +326,6 @@ app.registerExtension({
|
||||
min_max(this)
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
if (node.type === 'IntNumber') {
|
||||
@@ -340,22 +334,128 @@ app.registerExtension({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.TESTNODE_',
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
|
||||
if (nodeType.comfyClass == 'TESTNODE_') {
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted;
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments);
|
||||
console.log('##',message)
|
||||
|
||||
};
|
||||
|
||||
|
||||
const onExecuted = nodeType.prototype.onExecuted
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
onExecuted?.apply(this, arguments)
|
||||
console.log('##', message)
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
app.registerExtension({
|
||||
name: 'Mixlab.utils.KeyInput',
|
||||
init () {},
|
||||
async getCustomWidgets (app) {
|
||||
return {
|
||||
KEY (node, inputName, inputData, app) {
|
||||
// console.log('##node', node)
|
||||
const widget = {
|
||||
type: inputData[0], // the type, CHEESE
|
||||
name: inputName, // the name, slice
|
||||
size: [128, 32], // a default size
|
||||
draw (ctx, node, width, y) {},
|
||||
computeSize (...args) {
|
||||
return [128, 32] // a method to compute the current size of the widget
|
||||
},
|
||||
async serializeValue (nodeId, widgetIndex) {
|
||||
let data = getLocalData('_mixlab_api_key')
|
||||
return data[node.id] || 'by Mixlab'
|
||||
}
|
||||
}
|
||||
// widget.something = something; // maybe adds stuff to it
|
||||
node.addCustomWidget(widget) // adds it to the node
|
||||
return widget // and returns it.
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async beforeRegisterNodeDef (nodeType, nodeData, app) {
|
||||
if (nodeType.comfyClass == 'KeyInput') {
|
||||
const orig_nodeCreated = nodeType.prototype.onNodeCreated
|
||||
nodeType.prototype.onNodeCreated = function () {
|
||||
orig_nodeCreated?.apply(this, arguments)
|
||||
|
||||
const widget = {
|
||||
type: 'div',
|
||||
name: 'key_inp',
|
||||
draw (ctx, node, widget_width, y, widget_height) {
|
||||
Object.assign(
|
||||
this.div.style,
|
||||
get_position_style(ctx, widget_width, 44, node.size[1])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
widget.div = $el('div', {})
|
||||
|
||||
const inputDiv = (key, placeholder) => {
|
||||
let div = document.createElement('div')
|
||||
const ip = document.createElement('input')
|
||||
ip.type = placeholder === 'Key' ? 'password' : 'text'
|
||||
ip.className = `${'comfy-multiline-input'} ${placeholder}`
|
||||
div.style = `display: flex;
|
||||
align-items: center;
|
||||
margin: 6px 8px;
|
||||
margin-top: 0;`
|
||||
ip.placeholder = placeholder
|
||||
ip.value = placeholder
|
||||
|
||||
ip.style = `margin-left: 24px;
|
||||
outline: none;
|
||||
border: none;
|
||||
padding: 4px;width: 100%;`
|
||||
const label = document.createElement('label')
|
||||
label.style = 'font-size: 10px;min-width:32px'
|
||||
label.innerText = placeholder
|
||||
div.appendChild(label)
|
||||
div.appendChild(ip)
|
||||
|
||||
ip.addEventListener('change', () => {
|
||||
let data = getLocalData(key)
|
||||
data[this.id] = ip.value.trim()
|
||||
localStorage.setItem(key, JSON.stringify(data))
|
||||
console.log(this.id, key)
|
||||
})
|
||||
return div
|
||||
}
|
||||
|
||||
let inputKey = inputDiv('_mixlab_api_key', 'Key')
|
||||
|
||||
widget.div.appendChild(inputKey)
|
||||
|
||||
this.addCustomWidget(widget)
|
||||
|
||||
console.log('KeyInput nodeData',widget.div)
|
||||
|
||||
|
||||
const onRemoved = this.onRemoved
|
||||
this.onRemoved = () => {
|
||||
inputKey.remove()
|
||||
widget.div.remove()
|
||||
return onRemoved?.()
|
||||
}
|
||||
|
||||
this.serialize_widgets = true //需要保存参数
|
||||
}
|
||||
}
|
||||
},
|
||||
async loadedGraphNode (node, app) {
|
||||
// Fires every time a node is constructed
|
||||
// You can modify widgets/add handlers/etc here
|
||||
|
||||
if (node.type === 'KeyInput') {
|
||||
let widget = node.widgets.filter(w => w.div)[0]
|
||||
|
||||
let apiKey = getLocalData('_mixlab_api_key');
|
||||
|
||||
let id = node.id
|
||||
|
||||
widget.div.querySelector('.Key').value = apiKey[id] || 'by Mixlab'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user