diff --git a/Rayko_Models_Loader.py b/Rayko_Models_Loader.py index 1ed795e..9327518 100644 --- a/Rayko_Models_Loader.py +++ b/Rayko_Models_Loader.py @@ -2,7 +2,7 @@ import folder_paths import comfy.sd import json import os -from nodes import UNETLoader, CLIPLoader, VAELoader, LoraLoader +from nodes import UNETLoader, CLIPLoader, VAELoader, LoraLoader, DualCLIPLoader from server import PromptServer import aiohttp @@ -24,7 +24,9 @@ class RaykoModelsLoader: required = { "unet_name": (unet_files, {"tooltip": "Diffusion model (UNET)"}), "weight_dtype": (weight_dtype_opts, {"default": "default"}), - "clip_name": (clip_files, {"tooltip": "model CLIP"}), + "use_clip2": ("BOOLEAN", {"default": False, "label": "Enable second CLIP"}), + "clip_name": (clip_files, {"tooltip": "First CLIP model (or primary CLIP for dual mode)"}), + "clip_name2": (clip_files, {"tooltip": "Second CLIP model (for dual-clip models like Flux, SD3)"}), "clip_type": (clip_type_opts, {"default": "stable_diffusion"}), "clip_device": (device_opts, {"default": "default"}), "vae_name": (vae_files, {"tooltip": "model VAE"}), @@ -45,9 +47,10 @@ class RaykoModelsLoader: lora_data = "[]" return hashlib.md5(lora_data.encode()).hexdigest() - def load_models(self, unet_name, weight_dtype, clip_name, clip_type, clip_device, vae_name, lora_data="[]"): + def load_models(self, unet_name, weight_dtype, use_clip2, clip_name, clip_name2, clip_type, clip_device, vae_name, lora_data="[]"): print(f"\n[Rayko] === Start load_models ===") print(f"[Rayko] lora_data RAW: {lora_data}") + print(f"[Rayko] use_clip2: {use_clip2}") if not lora_data: lora_data = "[]" @@ -57,8 +60,29 @@ class RaykoModelsLoader: print(f"[Rayko] UNET: {unet_name}") dev = None if clip_device == "default" else clip_device - clip = CLIPLoader().load_clip(clip_name=clip_name, type=clip_type, device=dev)[0] - print(f"[Rayko] CLIP: {clip_name}") + + # CLIP loading logic with dual CLIP support + if use_clip2 and clip_name2 and clip_name2 != "None": + print(f"[Rayko] Using DualCLIPLoader mode") + print(f"[Rayko] CLIP1: {clip_name}") + print(f"[Rayko] CLIP2: {clip_name2}") + print(f"[Rayko] CLIP type: {clip_type}") + clip = DualCLIPLoader().load_clip( + clip_name1=clip_name, + clip_name2=clip_name2, + type=clip_type, + device=dev + )[0] + else: + print(f"[Rayko] Using standard CLIPLoader mode") + print(f"[Rayko] CLIP: {clip_name}") + print(f"[Rayko] CLIP type: {clip_type}") + clip = CLIPLoader().load_clip( + clip_name=clip_name, + type=clip_type, + device=dev + )[0] + print(f"[Rayko] CLIP loaded successfully") vae = VAELoader().load_vae(vae_name=vae_name)[0] print(f"[Rayko] VAE: {vae_name}") diff --git a/prompts/111.json b/prompts/111.json new file mode 100644 index 0000000..c316917 --- /dev/null +++ b/prompts/111.json @@ -0,0 +1,3 @@ +{ + "text": "Simple illustration of A photo-realistic shoot from a front angle about a professional couple in formal attire standing confidently with crossed arms in an office setting. the image also shows a woman and a man standing side by side, both dressed in business attire. on the left of the image, a woman with long blonde hair and fair skin appears to be standing confidently with her arms crossed, wearing a white blouse and a beige skirt. she has a serious expression and is looking directly at the camera. on the right of the image, a man with short dark hair and a beard is standing confidently with his arms crossed, wearing a navy blue suit and white shirt. he has a serious expression and is looking directly at the camera. the background is a modern office with large windows, allowing natural light to enter the space. the lighting is soft and natural, creating a professional atmosphere." +} \ No newline at end of file diff --git a/prompts/Замена одежды AGSoft.json b/prompts/Замена одежды AGSoft.json new file mode 100644 index 0000000..beb649a --- /dev/null +++ b/prompts/Замена одежды AGSoft.json @@ -0,0 +1,3 @@ +{ + "text": "\u0417\u0430\u043c\u0435\u043d\u0438 \u043e\u0434\u0435\u0436\u0434\u0443 \u0434\u0435\u0432\u0443\u0448\u043a\u0438 \u043d\u0430 \u0447\u0435\u0440\u043d\u044b\u0435 \u043a\u043e\u0436\u0430\u043d\u044b\u0439 \u043a\u043e\u0441\u0442\u044e\u043c \u0431\u0430\u0439\u043a\u0435\u0440\u0448\u0438." +} \ No newline at end of file diff --git a/prompts/Замена позы AGSoft.json b/prompts/Замена позы AGSoft.json new file mode 100644 index 0000000..cd47f86 --- /dev/null +++ b/prompts/Замена позы AGSoft.json @@ -0,0 +1,3 @@ +{ + "text": "change the poses in Image 1 to match those in Image 2, upscale to image" +} \ No newline at end of file diff --git a/prompts/Замена человека AGSoft.json b/prompts/Замена человека AGSoft.json new file mode 100644 index 0000000..1a28174 --- /dev/null +++ b/prompts/Замена человека AGSoft.json @@ -0,0 +1,3 @@ +{ + "text": "replace the woman in Image 1 with the person in Image 2, \u0441\u043e\u0433\u043b\u0430\u0441\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u0449\u0443\u044e \u0446\u0432\u0435\u0442\u043e\u0432\u0443\u044e \u0433\u0430\u043c\u043c\u0443, upscale to image" +} \ No newline at end of file diff --git a/prompts/Перенос одежды AGSoft.json b/prompts/Перенос одежды AGSoft.json new file mode 100644 index 0000000..947f52e --- /dev/null +++ b/prompts/Перенос одежды AGSoft.json @@ -0,0 +1,3 @@ +{ + "text": "\u0423\u0434\u0430\u043b\u0438 \u0432\u0441\u044e \u043e\u0434\u0435\u0436\u0434\u0443. \u0417\u0430\u043c\u0435\u043d\u0438 \u043d\u0430\u0440\u044f\u0434 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 from image2.\n\u0417\u0430\u043c\u0435\u043d\u0438 \u0442\u0443\u0444\u043b\u0438 \u043d\u0430 \u043a\u0440\u043e\u0441\u043e\u0432\u043a\u0438 from image2.\n\u041f\u0435\u0440\u0435\u043d\u0435\u0441\u0438 \u0447\u0430\u0441\u044b, \u0443\u043a\u0440\u0430\u0448\u0435\u043d\u0438\u044f \u0438 \u0430\u043a\u0441\u0435\u0441\u0441\u0443\u0430\u0440\u044b from image2." +} \ No newline at end of file diff --git a/prompts/Пятиминутка.json b/prompts/Пятиминутка.json new file mode 100644 index 0000000..f995a30 --- /dev/null +++ b/prompts/Пятиминутка.json @@ -0,0 +1,3 @@ +{ + "text": "Create a minimalistic tourist poster with double exposure.\nThe main plot is a modern broom in equipment, depicted in a clear silhouette in profile. The subject is wearing a protective military suit.\nInside the silhouette, use a double exposure effect filled with iconic visual effects, such as images inside a futuristic spaceship, architecture of the future, and an armed clash in a confined space. The composition should be mixed, soft and whole, not overloaded, with a clear focus.\nKeep the overall layout clean and elegant by using:\nbright or white background, soft gradient lighting, minimal distractions, smooth transitions between elements\nAdd a modern editorial headline in large, clear font in Russian:\n\"\u041f\u042f\u0422\u0418\u041c\u0418\u041d\u0423\u0422\u041a\u0410 \u041d\u0415\u041d\u0410\u0412\u0418\u0421\u0422\u0418\u201d\nThe design style should be similar to a premium movie poster, with:\nminimal composition\n, soft glow and cinematic lighting\n, high-end branding aesthetics\n, no clutter, no lively collages\n, balanced negative space\nFinal look: refined, modern, double-exposure poster, elegant, print-ready, ultra-detailed, 4K" +} \ No newline at end of file diff --git a/prompts/девушка в кресле.json b/prompts/девушка в кресле.json new file mode 100644 index 0000000..eafcdbd --- /dev/null +++ b/prompts/девушка в кресле.json @@ -0,0 +1,3 @@ +{ + "text": "A highly detailed and realistic digital painting of a woman sitting on a luxurious burgundy leather chair, wearing a black leather jacket and black high heels. the woman, who appears to be in her mid-twenties, has long, straight, dark brown hair that falls down her back, and her eyes are closed, giving off a mysterious and alluring expression. she is sitting in the middle of the image, with her legs crossed and her hands resting on the armrests of the chair. her body is slim and toned, and she is wearing a revealing black leather outfit that accentuates her figure. the background is a striking red and black abstract painting, with a high-quality texture that adds to the overall sense of sophistication and glamour. the chair itself is upholstered in a deep red velvet, and the woman's black heels add a touch of sophistication to her overall look. the overall effect is one of elegance and sophistication, making the viewer feel like they are in awe of the woman in her own world." +} \ No newline at end of file diff --git a/prompts/из фотки в рисунок AI Colab.json b/prompts/из фотки в рисунок AI Colab.json new file mode 100644 index 0000000..7421873 --- /dev/null +++ b/prompts/из фотки в рисунок AI Colab.json @@ -0,0 +1,3 @@ +{ + "text": "Simple illustration of" +} \ No newline at end of file diff --git a/web/rayko_lora_widget.js b/web/rayko_lora_widget.js index 066b9e9..f6fe224 100644 --- a/web/rayko_lora_widget.js +++ b/web/rayko_lora_widget.js @@ -35,6 +35,39 @@ app.registerExtension({ }; } + // Find widgets for CLIP2 disabled logic + const useClip2Widget = this.widgets.find(w => w.name === "use_clip2"); + const clipName2Widget = this.widgets.find(w => w.name === "clip_name2"); + + if (useClip2Widget && clipName2Widget) { + // Set initial disabled state + clipName2Widget.disabled = !useClip2Widget.value; + + // Apply CSS class for visual styling + if (clipName2Widget.element) { + if (clipName2Widget.disabled) { + clipName2Widget.element.classList.add("comfy-disabled"); + } else { + clipName2Widget.element.classList.remove("comfy-disabled"); + } + } + + // Callback when use_clip2 changes + const originalCallback = useClip2Widget.callback; + useClip2Widget.callback = function(value) { + if (originalCallback) originalCallback(value); + clipName2Widget.disabled = !value; + if (clipName2Widget.element) { + if (clipName2Widget.disabled) { + clipName2Widget.element.classList.add("comfy-disabled"); + } else { + clipName2Widget.element.classList.remove("comfy-disabled"); + } + } + nodeRef.graph?.setDirtyCanvas(true, true); + }; + } + this.setSize([this.targetWidth, this.size[1]]); this.addWidget("button", "✔️ Update LoRA list", "", async () => { @@ -86,6 +119,21 @@ app.registerExtension({ this.isRestoring = false; const self = this; this.loadLoraList().then(() => self.updateUI()); + + // Restore disabled state of clip_name2 after configuration load + const useClip2Widget = this.widgets.find(w => w.name === "use_clip2"); + const clipName2Widget = this.widgets.find(w => w.name === "clip_name2"); + if (useClip2Widget && clipName2Widget) { + clipName2Widget.disabled = !useClip2Widget.value; + if (clipName2Widget.element) { + if (clipName2Widget.disabled) { + clipName2Widget.element.classList.add("comfy-disabled"); + } else { + clipName2Widget.element.classList.remove("comfy-disabled"); + } + } + } + return originalOnConfigure ? originalOnConfigure.apply(this, arguments) : undefined; };