Skip to content

Commit

Permalink
Merge pull request #111 from shadowcz007/v.11.0-PromptImage-node-图片和p…
Browse files Browse the repository at this point in the history
…rompt匹配

V0.11.0 PromptImage & PromptSimplification
  • Loading branch information
shadowcz007 authored Jan 5, 2024
2 parents be7ad0c + 062773d commit 1daa1a4
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 17 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ https://github.com/shadowcz007/comfyui-mixlab-nodes/assets/12645064/e7e77f90-e43
[add clip-interrogator](https://github.com/pharmapsychotic/clip-interrogator)

> PromptImage & PromptSimplification,Assist in simplifying prompt words, comparing images and prompt word nodes.

### Layers
> A new layer class node has been added, allowing you to separate the image into layers. After merging the images, you can input the controlnet for further processing.
Expand Down
3 changes: 2 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ def new_add_routes(self):


# 导入节点
from .nodes.PromptNode import RandomPrompt,PromptSlide,PromptSimplification
from .nodes.PromptNode import RandomPrompt,PromptSlide,PromptSimplification,PromptImage
from .nodes.ImageNode import NoiseImage,TransparentImage,GradientImage,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
Expand All @@ -521,6 +521,7 @@ def new_add_routes(self):
"RandomPrompt":RandomPrompt,
"PromptSlide":PromptSlide,
"PromptSimplification":PromptSimplification,
"PromptImage":PromptImage,
"ClipInterrogator":ClipInterrogator,
"NoiseImage":NoiseImage,
"GradientImage":GradientImage,
Expand Down
78 changes: 75 additions & 3 deletions nodes/PromptNode.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import random
import comfy.utils
import json
import os
import numpy as np
from urllib import request, parse


import folder_paths
from PIL import Image, ImageOps,ImageFilter,ImageEnhance,ImageDraw,ImageSequence, ImageFont
from PIL.PngImagePlugin import PngInfo
# def queue_prompt(prompt_workflow):
# p = {"prompt": prompt_workflow}
# data = json.dumps(p).encode('utf-8')
Expand Down Expand Up @@ -45,6 +47,9 @@
default_prompt1="\n".join([p.strip() for p in default_prompt1.split('\n') if p.strip()!=''])


def tensor2pil(image):
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))

def addWeight(text, weight=1):
if weight == 1:
return text
Expand Down Expand Up @@ -78,6 +83,73 @@ def prompt_delete_words(sentence, new_words_length):
# result = prompt_delete_words(sentence, new_words_length)
# print(result)

class PromptImage:
def __init__(self):
self.temp_dir = folder_paths.get_temp_directory()
self.type = "temp"
self.prefix_append = "PromptImage"
self.compress_level = 4

@classmethod
def INPUT_TYPES(s):
return {
"required": {
"prompts": ("STRING",
{
"multiline": True,
"default": '',
"dynamicPrompts": False
}),

"images": ("IMAGE",{"default": None}),
"save_to_image": (["enable", "disable"],),
}
}

RETURN_TYPES = ()

OUTPUT_NODE = True

INPUT_IS_LIST = True

FUNCTION = "run"

CATEGORY = "♾️Mixlab/prompt"

# 运行的函数
def run(self,prompts,images,save_to_image):
filename_prefix="mixlab_"
filename_prefix += self.prefix_append
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(
filename_prefix, self.temp_dir, images[0].shape[1], images[0].shape[0])
results = list()

save_to_image=save_to_image[0]=='enable'

for index in range(len(images)):
image=images[index]
img=tensor2pil(image)

metadata = None
if save_to_image:
metadata = PngInfo()
prompt_text=prompts[index]
if prompt_text is not None:
metadata.add_text("prompt_text", prompt_text)

file = f"{filename}_{index}_{counter:05}_.png"
img.save(os.path.join(full_output_folder, file), pnginfo=metadata, compress_level=self.compress_level)
results.append({
"filename": file,
"subfolder": subfolder,
"type": self.type
})
counter += 1

return { "ui": { "_images": results,"prompts":prompts } }




class PromptSimplification:
@classmethod
Expand Down
77 changes: 67 additions & 10 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,15 @@
height: 56px !important;
outline: 1px solid white;
}


/* 给prompt image 节点使用 */
.prompt_image {
color: #2f2f2f;
padding: 0 10px;
font-size: 12px;
width: 200px;
}
</style>
<!-- <script src="../../../scripts/api.js" type="module"></script> -->
<link href="/extensions/comfyui-mixlab-nodes/lib/photoswipe.min.css" rel="stylesheet">
Expand Down Expand Up @@ -603,7 +612,16 @@
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)) {

if (node.class_type == "ClipInterrogator") {
let div = document.createElement('div');
div.className = "show_text";
div.id = `output_${node.id}`;
div.innerText = '#ClipInterrogator: …… '
output_card.appendChild(div);
};

if (["SaveImage", "PreviewImage", "PromptImage"].includes(node.class_type)) {

let a = document.createElement('a');
a.id = `output_${node.id}`
Expand Down Expand Up @@ -1567,28 +1585,47 @@

}

if (val && type == "images" && output.querySelector(`#output_${id} img`)) {
if (val && (type == "images" || type == 'images_prompts') && output.querySelector(`#output_${id} img`)) {
let imgDiv = output.querySelector(`#output_${id}`)
imgDiv.style.display = 'none';

// 清空
// Array.from(imgDiv.parentElement.querySelectorAll('.output_images'), im => im.remove());

for (const v of val) {
let im = await createImage(v);

let url = v, prompt = ''

if (type == 'images_prompts') {
// 是个数组,多了对应的prompt
url = v[0];
prompt = v[1];
}

let im = await createImage(url);

// 构建新的
let a = document.createElement('a');
a.className = `${imgDiv.id} output_images`
a.setAttribute('data-pswp-width', im.naturalWidth);
a.setAttribute('data-pswp-height', im.naturalHeight);
a.setAttribute('target', "_blank");
a.setAttribute('href', v);
a.setAttribute('href', url);


let img = new Image();
// img;
img.src = v;
a.appendChild(img)
img.src = url;
a.appendChild(img);

if (prompt) {
a.style.textDecoration = 'none';
let p = document.createElement('p')
p.className = 'prompt_image'
p.innerText = prompt;
a.appendChild(p)
}

// imgDiv.parentElement.appendChild(a);
imgDiv.parentElement.insertBefore(a, imgDiv.parentElement.firstChild);
}
Expand Down Expand Up @@ -1747,10 +1784,10 @@
};

api.addEventListener("status", ({ detail }) => {
console.log("status", detail, detail.exec_info.queue_remaining);
console.log("status", detail, detail.exec_info?.queue_remaining);
try {
ui.status.update(`queue#${detail.exec_info.queue_remaining}`);
if (detail.exec_info.queue_remaining === 0) {
ui.status.update(`queue#${detail.exec_info?.queue_remaining}`);
if (detail.exec_info?.queue_remaining === 0) {
// 运行按钮重设
ui.submitButton.reset()
console.log('运行按钮重设')
Expand All @@ -1763,8 +1800,9 @@

api.addEventListener("progress", ({ detail }) => {
console.log("progress", detail);
const class_type = window._appData.data[detail?.node]?.class_type || ''
try {
ui.status.update(`${detail.value}/${detail.max}`);
ui.status.update(`${parseFloat(100 * detail.value / detail.max).toFixed(1)}% ${class_type}`);
ui.submitButton.running()
} catch (error) {

Expand All @@ -1778,6 +1816,12 @@
const text = detail?.output?.text;
const gifs = detail?.output?.gifs;

const prompt = detail?.output?.prompt;
const analysis = detail?.output?.analysis;

const _images = detail?.output?._images;
const prompts = detail?.output?.prompts;

if (images) {
// if (!images) return;

Expand All @@ -1787,6 +1831,15 @@
return `${url}/view?filename=${encodeURIComponent(img.filename)}&type=${img.type}&subfolder=${encodeURIComponent(img.subfolder)}&t=${+new Date()}`;
}), detail.node, 'images');

} else if (_images && prompts) {
let url = get_url();

show(Array.from(_images, (img, i) => {
return [`${url}/view?filename=${encodeURIComponent(img.filename)
}&type=${img.type}&subfolder=${encodeURIComponent(img.subfolder)
}&t=${+new Date()}`, prompts[i]];
}), detail.node, 'images_prompts');

} else if (text) {
ui.output.update("text", Array.isArray(text) ? text.join('\n\n') : text, detail.node)
} else if (gifs && gifs[0]) {
Expand All @@ -1795,9 +1848,13 @@
}&&format=${gifs[0].format}&t=${+new Date()}`;

show(src, detail.node, gifs[0].format.match('video') ? 'video' : 'image');
} else if (prompt && analysis) {
// #ClipInterrogator: ……
ui.output.update("text", `${prompt.join('\n\n')}\n${JSON.stringify(analysis, null, 2)}`, detail.node)
}



try {
ui.status.update(`executed_#${window._appData.data[detail.node]?.class_type}`);
ui.submitButton.reset()
Expand Down
2 changes: 1 addition & 1 deletion web/javascript/checkVersion_mixlab.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { app } from '../../../scripts/app.js'
const repoOwner = 'shadowcz007' // 替换为仓库的所有者
const repoName = 'comfyui-mixlab-nodes' // 替换为仓库的名称

const version = 'v0.10.0'
const version = 'v0.11.0'

fetch(`https://api.github.com/repos/${repoOwner}/${repoName}/releases/latest`)
.then(response => response.json())
Expand Down
Loading

0 comments on commit 1daa1a4

Please sign in to comment.