mirror of
https://github.com/hanzoui/mixlab-nodes.git
synced 2026-10-30 20:48:06 +00:00
283 lines
8.8 KiB
Python
283 lines
8.8 KiB
Python
import os,sys
|
|
import folder_paths
|
|
|
|
from PIL import Image
|
|
import importlib.util
|
|
|
|
import comfy.utils
|
|
import numpy as np
|
|
import json
|
|
import torch
|
|
import random
|
|
|
|
|
|
# from clip_interrogator import Config, Interrogator
|
|
|
|
|
|
global _available
|
|
_available=False
|
|
|
|
def is_installed(package):
|
|
try:
|
|
spec = importlib.util.find_spec(package)
|
|
except ModuleNotFoundError:
|
|
return False
|
|
return spec is not None
|
|
|
|
|
|
try:
|
|
if is_installed('clip_interrogator')==False:
|
|
import subprocess
|
|
|
|
# 安装
|
|
print('#pip install clip-interrogator==0.6.0')
|
|
|
|
result = subprocess.run([sys.executable, '-s', '-m', 'pip', 'install', 'clip-interrogator==0.6.0'], capture_output=True, text=True)
|
|
|
|
#检查命令执行结果
|
|
if result.returncode == 0:
|
|
print("#install success")
|
|
from clip_interrogator import Config, Interrogator
|
|
_available=True
|
|
else:
|
|
print("#install error")
|
|
|
|
else:
|
|
from clip_interrogator import Config, Interrogator
|
|
_available=True
|
|
|
|
except:
|
|
_available=False
|
|
|
|
try:
|
|
from transformers import AutoProcessor, BlipForConditionalGeneration
|
|
except:
|
|
_available=False
|
|
print('pls check transformers.__version__>=4.36.0:: AutoProcessor, BlipForConditionalGeneration')
|
|
|
|
|
|
|
|
def load_caption_model(model_path,config,t='blip-base'):
|
|
dtype=torch.float16 if config.device == 'cuda' else torch.float32
|
|
caption_model = BlipForConditionalGeneration.from_pretrained(model_path, torch_dtype=dtype)
|
|
|
|
caption_processor = AutoProcessor.from_pretrained(model_path)
|
|
|
|
caption_model.eval()
|
|
if not config.caption_offload:
|
|
caption_model = caption_model.to(config.device)
|
|
|
|
return (caption_model,caption_processor)
|
|
|
|
|
|
def get_clip_interrogator_path():
|
|
try:
|
|
return folder_paths.get_folder_paths('clip_interrogator')[0]
|
|
except:
|
|
return os.path.join(folder_paths.models_dir, "clip_interrogator")
|
|
|
|
|
|
cache_path=get_clip_interrogator_path()
|
|
|
|
caption_model_path=os.path.join(cache_path, "Salesforce","blip-image-captioning-base")
|
|
if not os.path.exists(caption_model_path):
|
|
print(f"## clip_interrogator_model not found: {caption_model_path}, pls download from https://huggingface.co/Salesforce/blip-image-captioning-base")
|
|
caption_model_path='Salesforce/blip-image-captioning-base'
|
|
|
|
|
|
# Tensor to PIL
|
|
def tensor2pil(image):
|
|
return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8))
|
|
|
|
# Convert PIL to Tensor
|
|
def pil2tensor(image):
|
|
return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0)
|
|
|
|
|
|
def image_analysis_fn(ci,image):
|
|
image = image.convert('RGB')
|
|
image_features = ci.image_to_features(image)
|
|
|
|
top_mediums = ci.mediums.rank(image_features, 5)
|
|
top_artists = ci.artists.rank(image_features, 5)
|
|
top_movements = ci.movements.rank(image_features, 5)
|
|
top_trendings = ci.trendings.rank(image_features, 5)
|
|
top_flavors = ci.flavors.rank(image_features, 5)
|
|
|
|
medium_ranks = {medium: sim for medium, sim in zip(top_mediums, ci.similarities(image_features, top_mediums))}
|
|
artist_ranks = {artist: sim for artist, sim in zip(top_artists, ci.similarities(image_features, top_artists))}
|
|
movement_ranks = {movement: sim for movement, sim in zip(top_movements, ci.similarities(image_features, top_movements))}
|
|
trending_ranks = {trending: sim for trending, sim in zip(top_trendings, ci.similarities(image_features, top_trendings))}
|
|
flavor_ranks = {flavor: sim for flavor, sim in zip(top_flavors, ci.similarities(image_features, top_flavors))}
|
|
|
|
return {
|
|
"medium_ranks":medium_ranks,
|
|
"artist_ranks":artist_ranks,
|
|
"movement_ranks":movement_ranks,
|
|
"trending_ranks":trending_ranks,
|
|
"flavor_ranks":flavor_ranks
|
|
}
|
|
|
|
|
|
def generate_sentences(data):
|
|
sentences = []
|
|
|
|
# Get the length of data
|
|
data_length = len(data)
|
|
|
|
# Use a recursive function to handle variable-length data
|
|
def generate_recursive(index, current_sentence, current_score):
|
|
# Check if recursion is complete
|
|
if index == data_length:
|
|
sentences.append({"sentence": current_sentence, "score": current_score})
|
|
return
|
|
|
|
# Get the current level data
|
|
current_data = data[index]
|
|
|
|
# Iterate through the current level data
|
|
for phrase in current_data:
|
|
sentence = current_sentence + ("," if current_sentence.strip() else "") + phrase
|
|
score = current_score + current_data[phrase]
|
|
generate_recursive(index + 1, sentence, score)
|
|
|
|
# Start recursive generation of sentences
|
|
generate_recursive(0, "", 0)
|
|
|
|
# Sort the generated sentences by score in descending order
|
|
sentences.sort(key=lambda x: x["score"], reverse=True)
|
|
|
|
def get_random_elements(elements, num):
|
|
return random.sample(elements, num)
|
|
|
|
ps = get_random_elements(sentences, 5)
|
|
ps = [s["sentence"] for s in sorted(ps, key=lambda x: x["score"], reverse=True)]
|
|
|
|
return ps
|
|
|
|
|
|
|
|
|
|
def image_to_prompt(ci,image, mode):
|
|
ci.config.chunk_size = 2048 if ci.config.clip_model_name == "ViT-L-14/openai" else 1024
|
|
ci.config.flavor_intermediate_count = 2048 if ci.config.clip_model_name == "ViT-L-14/openai" else 1024
|
|
image = image.convert('RGB')
|
|
if mode == 'best':
|
|
return ci.interrogate(image)
|
|
elif mode == 'classic':
|
|
return ci.interrogate_classic(image)
|
|
elif mode == 'fast':
|
|
return ci.interrogate_fast(image)
|
|
elif mode == 'negative':
|
|
return ci.interrogate_negative(image)
|
|
|
|
# image = Image.open(image_path).convert('RGB')
|
|
# ci = Interrogator(Config(clip_model_name="ViT-L-14/openai"))
|
|
# print(ci.interrogate(image))
|
|
|
|
|
|
class ClipInterrogator:
|
|
|
|
global _available
|
|
available=_available
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {"required": {
|
|
"image": ("IMAGE",),
|
|
"prompt_mode": (['fast','classic','best','negative'],),
|
|
"image_analysis": (["off","on"],),
|
|
},
|
|
|
|
# "optional":{
|
|
# "output":("CLIPINTERROGATOR", {"multiline": True,"default": "", "dynamicPrompts": False})
|
|
# },
|
|
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING","STRING",)
|
|
RETURN_NAMES = ("prompt","random_samples",)
|
|
|
|
FUNCTION = "run"
|
|
|
|
CATEGORY = "♾️Mixlab/Prompt"
|
|
OUTPUT_NODE = True
|
|
INPUT_IS_LIST = True
|
|
OUTPUT_IS_LIST = (True,True,)
|
|
global ci
|
|
ci = None
|
|
def run(self,image,prompt_mode,image_analysis):
|
|
global ci
|
|
|
|
prompt_mode=prompt_mode[0]
|
|
analysis=image_analysis[0]
|
|
|
|
prompt_result=[]
|
|
analysis_result=[]
|
|
|
|
# 进度条
|
|
pbar = comfy.utils.ProgressBar(len(image)*(2 if analysis=='on' else 1))
|
|
|
|
if ci==None:
|
|
config=Config(
|
|
clip_model_name="ViT-L-14/openai",
|
|
device="cuda" if torch.cuda.is_available() else "cpu",
|
|
download_cache=True,
|
|
clip_model_path=cache_path,
|
|
cache_path=cache_path
|
|
)
|
|
config.apply_low_vram_defaults()
|
|
|
|
caption_model,caption_processor=load_caption_model(caption_model_path,config)
|
|
|
|
config.caption_model= caption_model
|
|
config.caption_processor= caption_processor
|
|
|
|
ci = Interrogator(config)
|
|
# else:
|
|
# simple_lama.model.to("cuda" if torch.cuda.is_available() else "cpu")
|
|
|
|
for i in range(len(image)):
|
|
im=image[i]
|
|
|
|
im=tensor2pil(im)
|
|
im=im.convert('RGB')
|
|
|
|
if analysis=='on':
|
|
analysis_res=image_analysis_fn(ci,im)
|
|
analysis_result.append( analysis_res )
|
|
pbar.update(1)
|
|
|
|
prompt=image_to_prompt(ci,im,prompt_mode)
|
|
pbar.update(1)
|
|
prompt_result.append(prompt)
|
|
|
|
|
|
# result.save("inpainted.png")
|
|
if ci.config.clip_offload and not ci.clip_offloaded:
|
|
ci.clip_model = ci.clip_model.to('cpu')
|
|
ci.clip_offloaded = True
|
|
|
|
if ci.config.caption_offload and not ci.caption_offloaded:
|
|
ci.caption_model = ci.caption_model.to('cpu')
|
|
ci.caption_offloaded = True
|
|
|
|
# analysis_result=[]
|
|
# items = app.graph.getNodeById(31).widgets[2].value["items"]
|
|
|
|
random_samples=[]
|
|
|
|
for r in analysis_result:
|
|
random_sample = generate_sentences([r['medium_ranks'], r['artist_ranks'],r['movement_ranks'],r['trending_ranks'],r['flavor_ranks']])
|
|
for s in random_sample:
|
|
random_samples.append(s)
|
|
# print(len(random_samples))
|
|
# print('-----')
|
|
# print( random_samples)
|
|
return {
|
|
"ui":{
|
|
"prompt": prompt_result,
|
|
"analysis":analysis_result,
|
|
"random_samples":random_samples
|
|
},
|
|
"result": (prompt_result,random_samples,)} |