diff --git a/src/components/graph/SelectionToolbox.vue b/src/components/graph/SelectionToolbox.vue index d4cf408fcf..bbbeadef94 100644 --- a/src/components/graph/SelectionToolbox.vue +++ b/src/components/graph/SelectionToolbox.vue @@ -12,7 +12,6 @@ - @@ -35,7 +34,6 @@ import BypassButton from '@/components/graph/selectionToolbox/BypassButton.vue' import ColorPickerButton from '@/components/graph/selectionToolbox/ColorPickerButton.vue' import ConvertToSubgraphButton from '@/components/graph/selectionToolbox/ConvertToSubgraphButton.vue' import DeleteButton from '@/components/graph/selectionToolbox/DeleteButton.vue' -import EditModelButton from '@/components/graph/selectionToolbox/EditModelButton.vue' import ExecuteButton from '@/components/graph/selectionToolbox/ExecuteButton.vue' import ExtensionCommandButton from '@/components/graph/selectionToolbox/ExtensionCommandButton.vue' import HelpButton from '@/components/graph/selectionToolbox/HelpButton.vue' diff --git a/src/components/graph/selectionToolbox/EditModelButton.vue b/src/components/graph/selectionToolbox/EditModelButton.vue deleted file mode 100644 index d9f515ddd4..0000000000 --- a/src/components/graph/selectionToolbox/EditModelButton.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/src/composables/useCoreCommands.ts b/src/composables/useCoreCommands.ts index 80eeca78f7..fe6d112bba 100644 --- a/src/composables/useCoreCommands.ts +++ b/src/composables/useCoreCommands.ts @@ -16,7 +16,6 @@ import { import { Point } from '@/lib/litegraph/src/litegraph' import { api } from '@/scripts/api' import { app } from '@/scripts/app' -import { addFluxKontextGroupNode } from '@/scripts/fluxKontextEditNode' import { useDialogService } from '@/services/dialogService' import { useLitegraphService } from '@/services/litegraphService' import { useWorkflowService } from '@/services/workflowService' @@ -775,17 +774,6 @@ export function useCoreCommands(): ComfyCommand[] { versionAdded: moveSelectedNodesVersionAdded, function: () => moveSelectedNodes(([x, y], gridSize) => [x + gridSize, y]) }, - { - id: 'Comfy.Canvas.AddEditModelStep', - icon: 'pi pi-pen-to-square', - label: 'Add Edit Model Step', - versionAdded: '1.23.3', - function: async () => { - const node = app.canvas.selectedItems.values().next().value - if (!(node instanceof LGraphNode)) return - await addFluxKontextGroupNode(node) - } - }, { id: 'Comfy.Graph.ConvertToSubgraph', icon: 'pi pi-sitemap', diff --git a/src/locales/ar/commands.json b/src/locales/ar/commands.json index 760d0a1780..95b417dc1d 100644 --- a/src/locales/ar/commands.json +++ b/src/locales/ar/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "تصفح القوالب" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "إضافة خطوة تحرير النموذج" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "حذف العناصر المحددة" }, diff --git a/src/locales/ar/main.json b/src/locales/ar/main.json index af0549674a..8a9cc8b2cf 100644 --- a/src/locales/ar/main.json +++ b/src/locales/ar/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "حول ComfyUI", - "Add Edit Model Step": "إضافة خطوة تعديل النموذج", "Bottom Panel": "لوحة سفلية", "Browse Templates": "تصفح القوالب", "Bypass/Unbypass Selected Nodes": "تجاوز/إلغاء تجاوز العقد المحددة", diff --git a/src/locales/en/commands.json b/src/locales/en/commands.json index 5b0d9c445a..8508497e66 100644 --- a/src/locales/en/commands.json +++ b/src/locales/en/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "Browse Templates" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "Add Edit Model Step" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "Delete Selected Items" }, diff --git a/src/locales/en/main.json b/src/locales/en/main.json index b4c2537082..b6ed989a14 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -958,7 +958,6 @@ "Restart": "Restart", "Open 3D Viewer (Beta) for Selected Node": "Open 3D Viewer (Beta) for Selected Node", "Browse Templates": "Browse Templates", - "Add Edit Model Step": "Add Edit Model Step", "Delete Selected Items": "Delete Selected Items", "Zoom to fit": "Zoom to fit", "Move Selected Nodes Down": "Move Selected Nodes Down", diff --git a/src/locales/es/commands.json b/src/locales/es/commands.json index 580515847e..d41962c03b 100644 --- a/src/locales/es/commands.json +++ b/src/locales/es/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "Explorar plantillas" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "Agregar paso de edición de modelo" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "Eliminar elementos seleccionados" }, diff --git a/src/locales/es/main.json b/src/locales/es/main.json index e056b0afb3..ef27fc8c28 100644 --- a/src/locales/es/main.json +++ b/src/locales/es/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "Acerca de ComfyUI", - "Add Edit Model Step": "Agregar paso de edición de modelo", "Bottom Panel": "Panel inferior", "Browse Templates": "Explorar plantillas", "Bypass/Unbypass Selected Nodes": "Evitar/No evitar nodos seleccionados", diff --git a/src/locales/fr/commands.json b/src/locales/fr/commands.json index 69a9f4fc32..e04e372b41 100644 --- a/src/locales/fr/commands.json +++ b/src/locales/fr/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "Parcourir les modèles" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "Ajouter/Modifier une étape de modèle" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "Supprimer les éléments sélectionnés" }, diff --git a/src/locales/fr/main.json b/src/locales/fr/main.json index 3680db24eb..31dcbe86f6 100644 --- a/src/locales/fr/main.json +++ b/src/locales/fr/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "À propos de ComfyUI", - "Add Edit Model Step": "Ajouter une étape d’édition de modèle", "Bottom Panel": "Panneau inférieur", "Browse Templates": "Parcourir les modèles", "Bypass/Unbypass Selected Nodes": "Contourner/Ne pas contourner les nœuds sélectionnés", diff --git a/src/locales/ja/commands.json b/src/locales/ja/commands.json index caaf7732d0..307ef72e56 100644 --- a/src/locales/ja/commands.json +++ b/src/locales/ja/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "テンプレートを参照" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "編集モデルステップを追加" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "選択したアイテムを削除" }, diff --git a/src/locales/ja/main.json b/src/locales/ja/main.json index 34caa47a24..c3af5ee251 100644 --- a/src/locales/ja/main.json +++ b/src/locales/ja/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "ComfyUIについて", - "Add Edit Model Step": "モデル編集ステップを追加", "Bottom Panel": "下部パネル", "Browse Templates": "テンプレートを参照", "Bypass/Unbypass Selected Nodes": "選択したノードのバイパス/バイパス解除", diff --git a/src/locales/ko/commands.json b/src/locales/ko/commands.json index 7105cd8212..431ae7ae00 100644 --- a/src/locales/ko/commands.json +++ b/src/locales/ko/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "템플릿 탐색" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "모델 편집 단계 추가" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "선택한 항목 삭제" }, diff --git a/src/locales/ko/main.json b/src/locales/ko/main.json index 672fad4fca..f11bc201f0 100644 --- a/src/locales/ko/main.json +++ b/src/locales/ko/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "ComfyUI에 대하여", - "Add Edit Model Step": "모델 편집 단계 추가", "Bottom Panel": "하단 패널", "Browse Templates": "템플릿 탐색", "Bypass/Unbypass Selected Nodes": "선택한 노드 우회/우회 해제", diff --git a/src/locales/ru/commands.json b/src/locales/ru/commands.json index fa3927190b..86fc88f176 100644 --- a/src/locales/ru/commands.json +++ b/src/locales/ru/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "Просмотр шаблонов" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "Добавить или изменить шаг модели" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "Удалить выбранные элементы" }, diff --git a/src/locales/ru/main.json b/src/locales/ru/main.json index 3257bc1b11..04e2b2bef8 100644 --- a/src/locales/ru/main.json +++ b/src/locales/ru/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "О ComfyUI", - "Add Edit Model Step": "Добавить или изменить шаг модели", "Bottom Panel": "Нижняя панель", "Browse Templates": "Просмотреть шаблоны", "Bypass/Unbypass Selected Nodes": "Обойти/восстановить выбранные ноды", diff --git a/src/locales/zh-TW/commands.json b/src/locales/zh-TW/commands.json index 71d1907b6f..46fbcb30d5 100644 --- a/src/locales/zh-TW/commands.json +++ b/src/locales/zh-TW/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "瀏覽範本" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "新增編輯模型步驟" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "刪除選取項目" }, diff --git a/src/locales/zh-TW/main.json b/src/locales/zh-TW/main.json index b61ea22cc5..fe0d5f4168 100644 --- a/src/locales/zh-TW/main.json +++ b/src/locales/zh-TW/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "關於 ComfyUI", - "Add Edit Model Step": "新增編輯模型步驟", "Bottom Panel": "底部面板", "Browse Templates": "瀏覽範本", "Bypass/Unbypass Selected Nodes": "繞過/取消繞過選取節點", diff --git a/src/locales/zh/commands.json b/src/locales/zh/commands.json index a42111c547..5d319aa170 100644 --- a/src/locales/zh/commands.json +++ b/src/locales/zh/commands.json @@ -41,9 +41,6 @@ "Comfy_BrowseTemplates": { "label": "浏览模板" }, - "Comfy_Canvas_AddEditModelStep": { - "label": "添加编辑模型步骤" - }, "Comfy_Canvas_DeleteSelectedItems": { "label": "删除选定的项目" }, diff --git a/src/locales/zh/main.json b/src/locales/zh/main.json index 6c678c651a..19b6533e82 100644 --- a/src/locales/zh/main.json +++ b/src/locales/zh/main.json @@ -762,7 +762,6 @@ }, "menuLabels": { "About ComfyUI": "关于ComfyUI", - "Add Edit Model Step": "添加编辑模型步骤", "Bottom Panel": "底部面板", "Browse Templates": "浏览模板", "Bypass/Unbypass Selected Nodes": "忽略/取消忽略选定节点", diff --git a/src/scripts/fluxKontextEditNode.ts b/src/scripts/fluxKontextEditNode.ts deleted file mode 100644 index fe794d43cc..0000000000 --- a/src/scripts/fluxKontextEditNode.ts +++ /dev/null @@ -1,693 +0,0 @@ -import _ from 'es-toolkit/compat' - -import { - type INodeOutputSlot, - type LGraph, - type LGraphNode, - LLink, - LiteGraph, - type Point -} from '@/lib/litegraph/src/litegraph' -import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets' -import { parseFilePath } from '@/utils/formatUtil' - -import { app } from './app' - -const fluxKontextGroupNode = { - nodes: [ - { - id: -1, - type: 'Reroute', - pos: [2354.87890625, -127.23468780517578], - size: [75, 26], - flags: {}, - order: 20, - mode: 0, - inputs: [{ name: '', type: '*', link: null }], - outputs: [{ name: '', type: '*', links: null }], - properties: { showOutputText: false, horizontal: false }, - index: 0 - }, - { - id: -1, - type: 'ReferenceLatent', - pos: [2730, -220], - size: [197.712890625, 46], - flags: {}, - order: 22, - mode: 0, - inputs: [ - { - localized_name: 'conditioning', - name: 'conditioning', - type: 'CONDITIONING', - link: null - }, - { - localized_name: 'latent', - name: 'latent', - shape: 7, - type: 'LATENT', - link: null - } - ], - outputs: [ - { - localized_name: 'CONDITIONING', - name: 'CONDITIONING', - type: 'CONDITIONING', - links: [] - } - ], - properties: { - 'Node name for S&R': 'ReferenceLatent', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - index: 1 - }, - { - id: -1, - type: 'VAEDecode', - pos: [3270, -110], - size: [210, 46], - flags: {}, - order: 25, - mode: 0, - inputs: [ - { - localized_name: 'samples', - name: 'samples', - type: 'LATENT', - link: null - }, - { - localized_name: 'vae', - name: 'vae', - type: 'VAE', - link: null - } - ], - outputs: [ - { - localized_name: 'IMAGE', - name: 'IMAGE', - type: 'IMAGE', - slot_index: 0, - links: [] - } - ], - properties: { - 'Node name for S&R': 'VAEDecode', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - index: 2 - }, - { - id: -1, - type: 'KSampler', - pos: [2930, -110], - size: [315, 262], - flags: {}, - order: 24, - mode: 0, - inputs: [ - { - localized_name: 'model', - name: 'model', - type: 'MODEL', - link: null - }, - { - localized_name: 'positive', - name: 'positive', - type: 'CONDITIONING', - link: null - }, - { - localized_name: 'negative', - name: 'negative', - type: 'CONDITIONING', - link: null - }, - { - localized_name: 'latent_image', - name: 'latent_image', - type: 'LATENT', - link: null - }, - { - localized_name: 'seed', - name: 'seed', - type: 'INT', - widget: { name: 'seed' }, - link: null - }, - { - localized_name: 'steps', - name: 'steps', - type: 'INT', - widget: { name: 'steps' }, - link: null - }, - { - localized_name: 'cfg', - name: 'cfg', - type: 'FLOAT', - widget: { name: 'cfg' }, - link: null - }, - { - localized_name: 'sampler_name', - name: 'sampler_name', - type: 'COMBO', - widget: { name: 'sampler_name' }, - link: null - }, - { - localized_name: 'scheduler', - name: 'scheduler', - type: 'COMBO', - widget: { name: 'scheduler' }, - link: null - }, - { - localized_name: 'denoise', - name: 'denoise', - type: 'FLOAT', - widget: { name: 'denoise' }, - link: null - } - ], - outputs: [ - { - localized_name: 'LATENT', - name: 'LATENT', - type: 'LATENT', - slot_index: 0, - links: [] - } - ], - properties: { - 'Node name for S&R': 'KSampler', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: [972054013131369, 'fixed', 20, 1, 'euler', 'simple', 1], - index: 3 - }, - { - id: -1, - type: 'FluxGuidance', - pos: [2940, -220], - size: [211.60000610351562, 58], - flags: {}, - order: 23, - mode: 0, - inputs: [ - { - localized_name: 'conditioning', - name: 'conditioning', - type: 'CONDITIONING', - link: null - }, - { - localized_name: 'guidance', - name: 'guidance', - type: 'FLOAT', - widget: { name: 'guidance' }, - link: null - } - ], - outputs: [ - { - localized_name: 'CONDITIONING', - name: 'CONDITIONING', - type: 'CONDITIONING', - slot_index: 0, - links: [] - } - ], - properties: { - 'Node name for S&R': 'FluxGuidance', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: [2.5], - index: 4 - }, - { - id: -1, - type: 'SaveImage', - pos: [3490, -110], - size: [985.3012084960938, 1060.3828125], - flags: {}, - order: 26, - mode: 0, - inputs: [ - { - localized_name: 'images', - name: 'images', - type: 'IMAGE', - link: null - }, - { - localized_name: 'filename_prefix', - name: 'filename_prefix', - type: 'STRING', - widget: { name: 'filename_prefix' }, - link: null - } - ], - outputs: [], - properties: { cnr_id: 'comfy-core', ver: '0.3.38' }, - widgets_values: ['ComfyUI'], - index: 5 - }, - { - id: -1, - type: 'CLIPTextEncode', - pos: [2500, -110], - size: [422.84503173828125, 164.31304931640625], - flags: {}, - order: 12, - mode: 0, - inputs: [ - { - localized_name: 'clip', - name: 'clip', - type: 'CLIP', - link: null - }, - { - localized_name: 'text', - name: 'text', - type: 'STRING', - widget: { name: 'text' }, - link: null - } - ], - outputs: [ - { - localized_name: 'CONDITIONING', - name: 'CONDITIONING', - type: 'CONDITIONING', - slot_index: 0, - links: [] - } - ], - title: 'CLIP Text Encode (Positive Prompt)', - properties: { - 'Node name for S&R': 'CLIPTextEncode', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: ['there is a bright light'], - color: '#232', - bgcolor: '#353', - index: 6 - }, - { - id: -1, - type: 'CLIPTextEncode', - pos: [2504.1435546875, 97.9598617553711], - size: [422.84503173828125, 164.31304931640625], - flags: { collapsed: true }, - order: 13, - mode: 0, - inputs: [ - { - localized_name: 'clip', - name: 'clip', - type: 'CLIP', - link: null - }, - { - localized_name: 'text', - name: 'text', - type: 'STRING', - widget: { name: 'text' }, - link: null - } - ], - outputs: [ - { - localized_name: 'CONDITIONING', - name: 'CONDITIONING', - type: 'CONDITIONING', - slot_index: 0, - links: [] - } - ], - title: 'CLIP Text Encode (Negative Prompt)', - properties: { - 'Node name for S&R': 'CLIPTextEncode', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: [''], - color: '#322', - bgcolor: '#533', - index: 7 - }, - { - id: -1, - type: 'UNETLoader', - pos: [2630, -370], - size: [270, 82], - flags: {}, - order: 6, - mode: 0, - inputs: [ - { - localized_name: 'unet_name', - name: 'unet_name', - type: 'COMBO', - widget: { name: 'unet_name' }, - link: null - }, - { - localized_name: 'weight_dtype', - name: 'weight_dtype', - type: 'COMBO', - widget: { name: 'weight_dtype' }, - link: null - } - ], - outputs: [ - { - localized_name: 'MODEL', - name: 'MODEL', - type: 'MODEL', - links: [] - } - ], - properties: { - 'Node name for S&R': 'UNETLoader', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: ['flux1-kontext-dev.safetensors', 'default'], - color: '#223', - bgcolor: '#335', - index: 8 - }, - { - id: -1, - type: 'DualCLIPLoader', - pos: [2100, -290], - size: [337.76861572265625, 130], - flags: {}, - order: 8, - mode: 0, - inputs: [ - { - localized_name: 'clip_name1', - name: 'clip_name1', - type: 'COMBO', - widget: { name: 'clip_name1' }, - link: null - }, - { - localized_name: 'clip_name2', - name: 'clip_name2', - type: 'COMBO', - widget: { name: 'clip_name2' }, - link: null - }, - { - localized_name: 'type', - name: 'type', - type: 'COMBO', - widget: { name: 'type' }, - link: null - }, - { - localized_name: 'device', - name: 'device', - shape: 7, - type: 'COMBO', - widget: { name: 'device' }, - link: null - } - ], - outputs: [ - { - localized_name: 'CLIP', - name: 'CLIP', - type: 'CLIP', - links: [] - } - ], - properties: { - 'Node name for S&R': 'DualCLIPLoader', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: [ - 'clip_l.safetensors', - 't5xxl_fp8_e4m3fn_scaled.safetensors', - 'flux', - 'default' - ], - color: '#223', - bgcolor: '#335', - index: 9 - }, - { - id: -1, - type: 'VAELoader', - pos: [2960, -370], - size: [270, 58], - flags: {}, - order: 7, - mode: 0, - inputs: [ - { - localized_name: 'vae_name', - name: 'vae_name', - type: 'COMBO', - widget: { name: 'vae_name' }, - link: null - } - ], - outputs: [ - { - localized_name: 'VAE', - name: 'VAE', - type: 'VAE', - links: [] - } - ], - properties: { - 'Node name for S&R': 'VAELoader', - cnr_id: 'comfy-core', - ver: '0.3.38' - }, - widgets_values: ['ae.safetensors'], - color: '#223', - bgcolor: '#335', - index: 10 - } - ], - links: [ - [6, 0, 1, 0, 72, 'CONDITIONING'], - [0, 0, 1, 1, 66, '*'], - [3, 0, 2, 0, 69, 'LATENT'], - [10, 0, 2, 1, 76, 'VAE'], - [8, 0, 3, 0, 74, 'MODEL'], - [4, 0, 3, 1, 70, 'CONDITIONING'], - [7, 0, 3, 2, 73, 'CONDITIONING'], - [0, 0, 3, 3, 66, '*'], - [1, 0, 4, 0, 67, 'CONDITIONING'], - [2, 0, 5, 0, 68, 'IMAGE'], - [9, 0, 6, 0, 75, 'CLIP'], - [9, 0, 7, 0, 75, 'CLIP'] - ], - external: [], - config: { - '0': {}, - '1': {}, - '2': { output: { '0': { visible: true } } }, - '3': { - output: { '0': { visible: true } }, - input: { - denoise: { visible: false }, - cfg: { visible: false } - } - }, - '4': {}, - '5': {}, - '6': {}, - '7': { input: { text: { visible: false } } }, - '8': { input: { weight_dtype: { visible: false } } }, - '9': { input: { type: { visible: false }, device: { visible: false } } }, - '10': {} - } -} - -export async function ensureGraphHasFluxKontextGroupNode( - graph: LGraph & { extra: { groupNodes?: Record } } -) { - graph.extra ??= {} - graph.extra.groupNodes ??= {} - if (graph.extra.groupNodes['FLUX.1 Kontext Image Edit']) return - - graph.extra.groupNodes['FLUX.1 Kontext Image Edit'] = - structuredClone(fluxKontextGroupNode) - - // Lazy import to avoid circular dependency issues - const { GroupNodeConfig } = await import('@/extensions/core/groupNode') - await GroupNodeConfig.registerFromWorkflow( - { - 'FLUX.1 Kontext Image Edit': - graph.extra.groupNodes['FLUX.1 Kontext Image Edit'] - }, - [] - ) -} - -export async function addFluxKontextGroupNode(fromNode: LGraphNode) { - const { canvas } = app - const { graph } = canvas - if (!graph) throw new TypeError('Graph is not initialized') - await ensureGraphHasFluxKontextGroupNode(graph) - - const node = LiteGraph.createNode('workflow>FLUX.1 Kontext Image Edit') - if (!node) throw new TypeError('Failed to create node') - - const pos = getPosToRightOfNode(fromNode) - - graph.add(node) - node.pos = pos - app.canvas.processSelect(node, undefined) - - connectPreviousLatent(fromNode, node) - - const symb = Object.getOwnPropertySymbols(node)[0] - // @ts-expect-error It's there -- promise. - node[symb].populateWidgets() - - setWidgetValues(node) -} - -function setWidgetValues(node: LGraphNode) { - const seedInput = node.widgets?.find((x) => x.name === 'seed') - if (!seedInput) throw new TypeError('Seed input not found') - seedInput.value = Math.floor(Math.random() * 1_125_899_906_842_624) - - const firstClip = node.widgets?.find((x) => x.name === 'clip_name1') - setPreferredValue('t5xxl_fp8_e4m3fn_scaled.safetensors', 't5xxl', firstClip) - - const secondClip = node.widgets?.find((x) => x.name === 'clip_name2') - setPreferredValue('clip_l.safetensors', 'clip_l', secondClip) - - const unet = node.widgets?.find((x) => x.name === 'unet_name') - setPreferredValue('flux1-dev-kontext_fp8_scaled.safetensors', 'kontext', unet) - - const vae = node.widgets?.find((x) => x.name === 'vae_name') - setPreferredValue('ae.safetensors', 'ae.s', vae) -} - -function setPreferredValue( - preferred: string, - match: string, - widget: IBaseWidget | undefined -): void { - if (!widget) throw new TypeError('Widget not found') - - const { values } = widget.options - if (!Array.isArray(values)) return - - // Match against filename portion only - const mapped = values.map((x) => parseFilePath(x).filename) - const value = - mapped.find((x) => x === preferred) ?? - mapped.find((x) => x.includes?.(match)) - widget.value = value ?? preferred -} - -function getPosToRightOfNode(fromNode: LGraphNode) { - const nodes = app.canvas.graph?.nodes - if (!nodes) throw new TypeError('Could not get graph nodes') - - const pos = [ - fromNode.pos[0] + fromNode.size[0] + 100, - fromNode.pos[1] - ] satisfies Point - - while (nodes.find((x) => isPointTooClose(x.pos, pos))) { - pos[0] += 20 - pos[1] += 20 - } - - return pos -} - -function connectPreviousLatent(fromNode: LGraphNode, toEditNode: LGraphNode) { - const { canvas } = app - const { graph } = canvas - if (!graph) throw new TypeError('Graph is not initialized') - - const l = findNearestOutputOfType([fromNode], 'LATENT') - if (!l) { - const imageOutput = findNearestOutputOfType([fromNode], 'IMAGE') - if (!imageOutput) throw new TypeError('No image output found') - - const vaeEncode = LiteGraph.createNode('VAEEncode') - if (!vaeEncode) throw new TypeError('Failed to create node') - - const { node: imageNode, index: imageIndex } = imageOutput - graph.add(vaeEncode) - vaeEncode.pos = getPosToRightOfNode(fromNode) - vaeEncode.pos[1] -= 200 - - vaeEncode.connect(0, toEditNode, 0) - imageNode.connect(imageIndex, vaeEncode, 0) - return - } - - const { node, index } = l - - node.connect(index, toEditNode, 0) -} - -function getInputNodes(node: LGraphNode): LGraphNode[] { - return node.inputs - .map((x) => LLink.resolve(x.link, app.graph)?.outputNode) - .filter((x) => !!x) -} - -function getOutputOfType( - node: LGraphNode, - type: string -): { - output: INodeOutputSlot - index: number -} { - const index = node.outputs.findIndex((x) => x.type === type) - const output = node.outputs[index] - return { output, index } -} - -function findNearestOutputOfType( - nodes: Iterable, - type: string = 'LATENT', - depth: number = 0 -): { node: LGraphNode; index: number } | undefined { - for (const node of nodes) { - const { output, index } = getOutputOfType(node, type) - if (output) return { node, index } - } - - if (depth < 3) { - const closestNodes = new Set([...nodes].flatMap((x) => getInputNodes(x))) - const res = findNearestOutputOfType(closestNodes, type, depth + 1) - if (res) return res - } -} - -function isPointTooClose(a: Point, b: Point, precision: number = 5) { - return Math.abs(a[0] - b[0]) < precision && Math.abs(a[1] - b[1]) < precision -}