diff --git a/README.en.md b/README.en.md index c7fc3a3..c99b47a 100644 --- a/README.en.md +++ b/README.en.md @@ -11,8 +11,6 @@ ## Introduce -**Incompatibility Notice**: Not compatible with the current version of the [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) node package at this time - ### Random species @@ -31,6 +29,11 @@ After installing the node package, the UI interface will be automatically switch ## Changelog +**Updated at 2023-12-25** + +- Fixed `easy globalSeed` is not working +- Fixed an issue where all `seed_num` values were out of order due to [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) updating the chart in real time + **v1.0.0(Updated at 12/24/2023 GMT+0800)** - Added `easy positive` - simple positive prompt text diff --git a/README.md b/README.md index 2b4517b..ca1c5ad 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,6 @@ ## 介绍 -**不兼容提示**:目前无法与 [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) 节点包当前版本兼容(该节点包的机制会导致序列化时随机种一直赋值等问题),可使用 **getNode**、**setNode** 替代。 - ### 更符合人性化的随机种 @@ -38,6 +36,11 @@ ## 更新日志 +**2023-12-25** + +- 修复 `easy globalSeed` 不生效问题 +- 修复所有的`seed_num` 因 [cg-use-everywhere](https://github.com/chrisgoringe/cg-use-everywhere) 实时更新图表导致值错乱的问题 + **v1.0.0(2023-12-24)** - 新增`easy positive` - 简易正面提示词文本 diff --git a/py/easyNodes.py b/py/easyNodes.py index e3c06d1..7f5fead 100644 --- a/py/easyNodes.py +++ b/py/easyNodes.py @@ -1027,14 +1027,14 @@ class wildcardsPrompt: my_unique_id = int(my_unique_id) easy_save = easySave(my_unique_id, prompt, extra_pnginfo) - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ - 'inputs'] else 0 - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ + # 'inputs'] else 0 + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num text = kwargs['text'] return {"ui": {"value": [seed_num]}, "result": (text,)} @@ -1985,14 +1985,14 @@ class samplerSettings: def settings(self, pipe, steps, cfg, sampler_name, scheduler, denoise, seed_num, image_to_latent=None, latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ - 'inputs'] else 0 - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ + # 'inputs'] else 0 + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num # 图生图转换 vae = pipe["vae"] @@ -2070,14 +2070,14 @@ class samplerSettingsAdvanced: def settings(self, pipe, steps, cfg, sampler_name, scheduler, start_at_step, end_at_step, add_noise, seed_num, image_to_latent=None, latent=None, prompt=None, extra_pnginfo=None, my_unique_id=None): - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ - 'inputs'] else 0 - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ + # 'inputs'] else 0 + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num # 图生图转换 vae = pipe["vae"] @@ -2192,14 +2192,14 @@ class sdTurboSettings: _sampler = comfy.samplers.sampler_object(sampler_name) extra_options = None - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ - 'inputs'] else 0 - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ + # 'inputs'] else 0 + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num new_pipe = { "model": pipe['model'], @@ -2278,13 +2278,14 @@ class dynamicCFGSettings: m = model.clone() m.set_model_sampler_cfg_function(sampler_dyn_thresh) - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id]['inputs'] else 0 - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] if 'seed_num' in prompt[my_unique_id][ + # 'inputs'] else 0 + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num new_pipe = { "model": m, @@ -2406,13 +2407,13 @@ class samplerFull: my_unique_id = int(my_unique_id) - if my_unique_id: - workflow = extra_pnginfo["workflow"] - node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) - if node and 'seed_num' in prompt[my_unique_id]['inputs']: - seed_num = prompt[my_unique_id]['inputs']['seed_num'] - length = len(node["widgets_values"]) - node["widgets_values"][length - 2] = seed_num + # if my_unique_id: + # workflow = extra_pnginfo["workflow"] + # node = next((x for x in workflow["nodes"] if str(x["id"]) == my_unique_id), None) + # if node and 'seed_num' in prompt[my_unique_id]['inputs']: + # seed_num = prompt[my_unique_id]['inputs']['seed_num'] + # length = len(node["widgets_values"]) + # node["widgets_values"][length - 2] = seed_num easy_save = easySave(my_unique_id, prompt, extra_pnginfo) diff --git a/py/server.py b/py/server.py index fcee888..dc6c98d 100644 --- a/py/server.py +++ b/py/server.py @@ -8,6 +8,7 @@ class SGmode(Enum): DECR = 3 RAND = 4 + class SeedGenerator: def __init__(self, base_value, action): self.base_value = base_value @@ -38,9 +39,9 @@ class SeedGenerator: return seed -def control_seed(v): - action = v['inputs']['action'] - value = v['inputs']['value'] +def control_seed(v, action, seed_is_global): + action = action or v['inputs']['action'] + value = v['inputs']['value'] if seed_is_global else v['inputs']['seed_num'] if action == 'increment' or action == 'increment for each node': value += 1 @@ -53,7 +54,10 @@ def control_seed(v): elif action == 'randomize' or action == 'randomize for each node': value = random.randint(0, 1125899906842624) - v['inputs']['value'] = value + if seed_is_global: + v['inputs']['value'] = value + else: + v['inputs']['seed_num'] = value return value @@ -64,57 +68,83 @@ def prompt_seed_update(json_data): except: return None - seed_widget_map = json_data['extra_data']['extra_pnginfo']['workflow']['seed_widgets'] + workflow = json_data['extra_data']['extra_pnginfo']['workflow'] + seed_widget_map = workflow['seed_widgets'] value = None mode = None node = None action = None + seed_is_global = False for k, v in json_data['prompt'].items(): if 'class_type' not in v: continue cls = v['class_type'] - if cls == 'globalSeed': + + if cls == 'easy globalSeed': mode = v['inputs']['mode'] action = v['inputs']['action'] value = v['inputs']['value'] node = k, v + seed_is_global = True # control before generated - if mode is not None and mode: - value = control_seed(node[1]) + if mode is not None and mode and seed_is_global: + value = control_seed(node[1], action, seed_is_global) - if value is not None: - seed_generator = SeedGenerator(value, action) + if seed_is_global: + if value is not None: + seed_generator = SeedGenerator(value, action) + for k, v in json_data['prompt'].items(): + for k2, v2 in v['inputs'].items(): + if isinstance(v2, str) and '$GlobalSeed.value$' in v2: + v['inputs'][k2] = v2.replace('$GlobalSeed.value$', str(value)) + + if k not in seed_widget_map: + continue + + if 'seed_num' in v['inputs']: + if isinstance(v['inputs']['seed_num'], int): + v['inputs']['seed_num'] = seed_generator.next() + + if 'seed' in v['inputs']: + if isinstance(v['inputs']['seed'], int): + v['inputs']['seed'] = seed_generator.next() + + if 'noise_seed' in v['inputs']: + if isinstance(v['inputs']['noise_seed'], int): + v['inputs']['noise_seed'] = seed_generator.next() + + for k2, v2 in v['inputs'].items(): + if isinstance(v2, str) and '$GlobalSeed.value$' in v2: + v['inputs'][k2] = v2.replace('$GlobalSeed.value$', str(value)) + # control after generated + if mode is not None and not mode: + control_seed(node[1], action, seed_is_global) + else: for k, v in json_data['prompt'].items(): - for k2, v2 in v['inputs'].items(): - if isinstance(v2, str) and '$GlobalSeed.value$' in v2: - v['inputs'][k2] = v2.replace('$GlobalSeed.value$', str(value)) - - if k not in seed_widget_map: + if 'class_type' not in v: continue + cls = v['class_type'] + if cls == "easy wildcards" or cls == "easy preSampling" or cls == "easy preSamplingAdvanced" or cls == "easy preSamplingSdTurbo" or cls == "easy preSamplingDynamicCFG" or cls == "easy fullkSampler": + extra_data = next((x for x in workflow["nodes"] if str(x["id"]) == k), None) + if extra_data is not None: + widgets_value = extra_data.get('widgets_values') + widgets_length = len(widgets_value) + action = widgets_value[widgets_length - 1] + node = k, v - if 'seed_num' in v['inputs']: - if isinstance(v['inputs']['seed_num'], int): - v['inputs']['seed'] = seed_generator.next() + value = control_seed(node[1], action, False) + _seed_generator = SeedGenerator(value, action) + print(value) + if k not in seed_widget_map: + continue - if 'seed' in v['inputs']: - if isinstance(v['inputs']['seed'], int): - v['inputs']['seed'] = seed_generator.next() - - if 'noise_seed' in v['inputs']: - if isinstance(v['inputs']['noise_seed'], int): - v['inputs']['noise_seed'] = seed_generator.next() - - for k2, v2 in v['inputs'].items(): - if isinstance(v2, str) and '$GlobalSeed.value$' in v2: - v['inputs'][k2] = v2.replace('$GlobalSeed.value$', str(value)) - - # control after generated - if mode is not None and not mode: - control_seed(node[1]) + if 'seed_num' in v['inputs']: + if isinstance(v['inputs']['seed_num'], int): + v['inputs']['seed_num'] = _seed_generator.next() return value is not None @@ -126,19 +156,22 @@ def workflow_seed_update(json_data): updated_seed_map = {} value = None + for node in nodes: node_id = str(node['id']) if node_id in prompt: - if node['type'] == 'globalSeed': + if node['type'] == 'easy globalSeed': value = prompt[node_id]['inputs']['value'] + length = len(node['widgets_values']) + node['widgets_values'][length-1] = node['widgets_values'][0] node['widgets_values'][0] = value elif node_id in seed_widget_map: widget_idx = seed_widget_map[node_id] - if 'noise_seed' in prompt[node_id]['inputs']: - seed = prompt[node_id]['inputs']['noise_seed'] - elif 'seed_num' in prompt[node_id]['inputs']: + if 'seed_num' in prompt[node_id]['inputs']: seed = prompt[node_id]['inputs']['seed_num'] + elif 'noise_seed' in prompt[node_id]['inputs']: + seed = prompt[node_id]['inputs']['noise_seed'] else: seed = prompt[node_id]['inputs']['seed'] @@ -147,6 +180,7 @@ def workflow_seed_update(json_data): server.PromptServer.instance.send_sync("easyuse-global-seed", {"id": node_id, "value": value, "seed_map": updated_seed_map}) + def onprompt(json_data): is_changed = prompt_seed_update(json_data) if is_changed: diff --git a/web/js/easy/easyDynamicWidgets.js b/web/js/easy/easyDynamicWidgets.js index 3f8c56f..6b82b12 100644 --- a/web/js/easy/easyDynamicWidgets.js +++ b/web/js/easy/easyDynamicWidgets.js @@ -325,21 +325,21 @@ app.registerExtension({ } if (["easy wildcards", "easy preSampling", "easy preSamplingAdvanced", "easy preSamplingSdTurbo", "easy preSamplingDynamicCFG", "easy fullkSampler"].includes(nodeData.name)) { - const control_seed = (action,seed) =>{ - switch (action){ - case 'randomize': - seed = Math.floor(Math.random() * 1125899906842624) - break - case 'increment': - seed = seed + 1 - break - case 'decrement': - seed = seed - 1 - break - } - return seed - } - + // const control_seed = (action,seed) =>{ + // switch (action){ + // case 'randomize': + // seed = Math.floor(Math.random() * 1125899906842624) + // break + // case 'increment': + // seed = seed + 1 + // break + // case 'decrement': + // seed = seed - 1 + // break + // } + // return seed + // } + // const onNodeCreated = nodeType.prototype.onNodeCreated; nodeType.prototype.onNodeCreated = async function () { onNodeCreated ? onNodeCreated.apply(this, []) : undefined; @@ -348,15 +348,15 @@ app.registerExtension({ values, serialize:false }) - let seedWidget = this.widgets.find(w=> w.name == "seed_num") - seedWidget.serializeValue = async (node, index) => { - const _seed = control_seed(seed_control.value,seedWidget.value) - if(node && node['widgets']){ - node['widgets'][index]['value'] = _seed - if(node['widgets_values'] && node['widgets_values'][index]) node['widgets_values'][index] = _seed - } - return _seed - } + // let seedWidget = this.widgets.find(w=> w.name == "seed_num") + // seedWidget.serializeValue = async (node, index) => { + // const _seed = control_seed(seed_control.value,seedWidget.value) + // if(node && node['widgets']){ + // node['widgets'][index]['value'] = _seed + // if(node['widgets_values'] && node['widgets_values'][index]) node['widgets_values'][index] = _seed + // } + // return _seed + // } } } }, diff --git a/web/js/easy/easyInterface.js b/web/js/easy/easyInterface.js index 22e4cd5..7c1ed02 100644 --- a/web/js/easy/easyInterface.js +++ b/web/js/easy/easyInterface.js @@ -794,96 +794,96 @@ app.registerExtension({ } }) -// 补充:解决control_before_generate时从历史记录调起时seed值不一致 -const element = document.getElementsByClassName('comfy-list') -let new_element = null -async function load(){ - const items = await api.getItems('history'); - new_element.replaceChildren( - ...Object.keys(items).flatMap((section) => [ - $el("h4", { - textContent: section, - }), - $el("div.comfy-list-items", [ - ...(items[section].reverse()).map((item) => { - // Allow items to specify a custom remove action (e.g. for interrupt current prompt) - const removeAction = item.remove || { - name: "Delete", - cb: () => api.deleteItem('history', item.prompt[1]), - }; - return $el("div", {textContent: item.prompt[0] + ": "}, [ - $el("button", { - textContent: "Load", - onclick: async () => { - // 补充:解决control_before_generate时从历史记录调起时seed值错误 - const outputs = item.outputs - let workflow = item.prompt[3].extra_pnginfo.workflow - const seed_widgets = workflow.seed_widgets - if(seed_widgets){ - for(let id in seed_widgets){ - id = parseInt(id) - if(outputs[id] && outputs[id]['value']){ - const seed = outputs[id]['value'][0] - let nodeIndex = workflow.nodes.findIndex(cate=>cate.id == id) - if(nodeIndex!==-1 && workflow.nodes[nodeIndex]){ - workflow.nodes[nodeIndex]['widgets_values'][seed_widgets[id]] = seed - } - } - } - } - // end - await app.loadGraphData(workflow); - if (item.outputs) { - app.nodeOutputs = item.outputs; - } - }, - }), - $el("button", { - textContent: removeAction.name, - onclick: async () => { - await removeAction.cb(); - if (new_element.style.display != 'none') { - await load(); - } - }, - }), - ]); - }), - ]), - ]), - $el("div.comfy-list-actions", [ - $el("button", { - textContent: "Clear History", - onclick: async () => { - await api.clearItems('history'); - await load(); - }, - }), - $el("button", {textContent: "Refresh", onclick: () => load()}), - ]) - ); -} -if(element && element[1]){ - const history_button = document.getElementById('comfy-view-history-button') - history_button.addEventListener('click',e=>{ - if(new_element){ - if(new_element.style.display == 'none') new_element.style.display = 'block' - else new_element.style.display = 'none' - } - if(element[1].style.display != 'none'){ - element[1].remove() - const parentNode = element[0].parentNode - new_element = document.createElement('div') - new_element.className = 'comfy-list easyuse' - new_element.style.display = 'block' - parentNode.insertBefore(new_element, element[0].nextSibling); - setTimeout(_=>load(),10) - } - }) -} -api.addEventListener("status", () => { - if (new_element && new_element.style.display != 'none') { - load(); - } -}); +// 不需要了,之前的解决方案(解决control_before_generate时从历史记录调起时seed值不一致) +// const element = document.getElementsByClassName('comfy-list') +// let new_element = null +// async function load(){ +// const items = await api.getItems('history'); +// new_element.replaceChildren( +// ...Object.keys(items).flatMap((section) => [ +// $el("h4", { +// textContent: section, +// }), +// $el("div.comfy-list-items", [ +// ...(items[section].reverse()).map((item) => { +// // Allow items to specify a custom remove action (e.g. for interrupt current prompt) +// const removeAction = item.remove || { +// name: "Delete", +// cb: () => api.deleteItem('history', item.prompt[1]), +// }; +// return $el("div", {textContent: item.prompt[0] + ": "}, [ +// $el("button", { +// textContent: "Load", +// onclick: async () => { +// // 补充:解决control_before_generate时从历史记录调起时seed值错误 +// const outputs = item.outputs +// let workflow = item.prompt[3].extra_pnginfo.workflow +// const seed_widgets = workflow.seed_widgets +// if(seed_widgets){ +// for(let id in seed_widgets){ +// id = parseInt(id) +// if(outputs[id] && outputs[id]['value']){ +// const seed = outputs[id]['value'][0] +// let nodeIndex = workflow.nodes.findIndex(cate=>cate.id == id) +// if(nodeIndex!==-1 && workflow.nodes[nodeIndex]){ +// workflow.nodes[nodeIndex]['widgets_values'][seed_widgets[id]] = seed +// } +// } +// } +// } +// // end +// await app.loadGraphData(workflow); +// if (item.outputs) { +// app.nodeOutputs = item.outputs; +// } +// }, +// }), +// $el("button", { +// textContent: removeAction.name, +// onclick: async () => { +// await removeAction.cb(); +// if (new_element.style.display != 'none') { +// await load(); +// } +// }, +// }), +// ]); +// }), +// ]), +// ]), +// $el("div.comfy-list-actions", [ +// $el("button", { +// textContent: "Clear History", +// onclick: async () => { +// await api.clearItems('history'); +// await load(); +// }, +// }), +// $el("button", {textContent: "Refresh", onclick: () => load()}), +// ]) +// ); +// } +// if(element && element[1]){ +// const history_button = document.getElementById('comfy-view-history-button') +// history_button.addEventListener('click',e=>{ +// if(new_element){ +// if(new_element.style.display == 'none') new_element.style.display = 'block' +// else new_element.style.display = 'none' +// } +// if(element[1].style.display != 'none'){ +// element[1].remove() +// const parentNode = element[0].parentNode +// new_element = document.createElement('div') +// new_element.className = 'comfy-list easyuse' +// new_element.style.display = 'block' +// parentNode.insertBefore(new_element, element[0].nextSibling); +// setTimeout(_=>load(),10) +// } +// }) +// } +// api.addEventListener("status", () => { +// if (new_element && new_element.style.display != 'none') { +// load(); +// } +// }); diff --git a/web/js/seed.js b/web/js/seed.js index 9bccf43..9dff246 100644 --- a/web/js/seed.js +++ b/web/js/seed.js @@ -5,7 +5,7 @@ function globalSeedHandler(event) { let nodes = app.graph._nodes_by_id; for(let i in nodes) { let node = nodes[i]; - if(node.type == 'globalSeed') { + if(node.type == 'easy globalSeed') { if(node.widgets) { const w = node.widgets.find((w) => w.name == 'value'); const last_w = node.widgets.find((w) => w.name == 'last_seed'); @@ -16,6 +16,7 @@ function globalSeedHandler(event) { else{ if(node.widgets) { const w = node.widgets.find((w) => w.name == 'seed_num' || w.name == 'seed' || w.name == 'noise_seed'); + console.log(w) if(w && event.detail.seed_map[node.id] != undefined) { w.value = event.detail.seed_map[node.id]; }