Files
hanL34-ComfyUI-Power-Artist…/nodes.py
T
2025-09-30 13:49:44 +08:00

211 lines
7.5 KiB
Python

import json
import os
import csv
from typing import Dict, List, Tuple, Any
from aiohttp import web
import aiofiles
from server import PromptServer
class PowerArtistLoader:
"""
Power Artist Loader Node - 修复版本
"""
def __init__(self):
self.artists_data = {}
self.load_artists_data()
def load_artists_data(self):
"""从CSV文件加载画师数据 - 使用分号分隔"""
csv_path = os.path.join(os.path.dirname(__file__), "artists.csv")
if os.path.exists(csv_path):
try:
with open(csv_path, 'r', encoding='utf-8') as f:
for line in f:
line = line.strip()
if not line:
continue
# 使用分号分隔:标题;keywords;图片
parts = line.split(';')
if len(parts) >= 2:
name = parts[0].strip()
keywords = parts[1].strip()
image = parts[2].strip() if len(parts) > 2 else None
self.artists_data[name] = {
'keywords': keywords,
'image': image
}
print(f"Loaded {len(self.artists_data)} artists from CSV")
except Exception as e:
print(f"Error loading artists.csv: {e}")
self.load_default_artists()
else:
# 创建示例CSV文件
self.create_example_csv(csv_path)
self.load_default_artists()
def create_example_csv(self, csv_path):
"""创建示例CSV文件 - 使用分号分隔"""
example_data = [
"Akira Toriyama;akira toriyama style, anime, dragon ball;toriyama.jpg",
"Hayao Miyazaki;hayao miyazaki, studio ghibli, anime film;miyazaki.jpg",
"Greg Rutkowski;greg rutkowski, artstation, fantasy art;rutkowski.jpg",
"厚涂风格;(WLOP:0.5), (Pablo Picasso:0.8), (Greg Rutkowski:1.1);houtu.jpg",
"Vincent van Gogh;vincent van gogh, post-impressionism, swirling brushstrokes;vangogh.jpg",
"Leonardo da Vinci;leonardo da vinci, renaissance, sfumato technique;davinci.jpg"
]
try:
with open(csv_path, 'w', encoding='utf-8') as f:
for line in example_data:
f.write(line + '\n')
print(f"Created example CSV file: {csv_path}")
except Exception as e:
print(f"Error creating example CSV: {e}")
def load_default_artists(self):
"""加载默认画师数据"""
self.artists_data = {
"Akira Toriyama": {"keywords": "akira toriyama style, anime, dragon ball", "image": "toriyama.jpg"},
"Hayao Miyazaki": {"keywords": "hayao miyazaki, studio ghibli, anime film", "image": "miyazaki.jpg"},
"Greg Rutkowski": {"keywords": "greg rutkowski, artstation, fantasy art", "image": "rutkowski.jpg"}
}
@classmethod
def INPUT_TYPES(cls):
return {
"required": {},
"optional": {},
"hidden": {
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
"unique_id": "UNIQUE_ID",
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
FUNCTION = "load_artists"
CATEGORY = "conditioning"
DESCRIPTION = "Load multiple artists and output keywords"
def load_artists(self, text="", prompt=None, extra_pnginfo=None, unique_id=None):
"""处理画师加载逻辑,输出keywords"""
enabled_keywords = []
if prompt and unique_id:
node_data = prompt.get(str(unique_id), {})
inputs = node_data.get("inputs", {})
# 处理artist widgets数据
for key, value in inputs.items():
if key.startswith("artist_") and isinstance(value, dict):
enabled = value.get("on", False)
artist_name = value.get("artist", "None")
weight = value.get("strength", 1.0)
if enabled and artist_name != "None":
# 获取画师的keywords
artist_data = self.artists_data.get(artist_name)
if artist_data:
keywords = artist_data.get("keywords", artist_name)
else:
# fallback到画师名
keywords = artist_name
# 移除开头的空格
keywords = keywords.strip()
if weight != 1.0:
# 格式化权重
weight_str = f"{weight:.2f}"
enabled_keywords.append(f"({keywords}:{weight_str})")
else:
enabled_keywords.append(keywords)
# 组合最终文本
result_text = text.strip() if text else ""
if enabled_keywords:
# 先组合,然后统一处理空格
keywords_text = ", ".join(enabled_keywords)
# 移除逗号后的空格:", " -> ","
keywords_text = keywords_text.replace(", ", ",")
if result_text:
result_text = f"{result_text},{keywords_text}"
else:
result_text = keywords_text
return (result_text,)
@classmethod
def IS_CHANGED(cls, **kwargs):
return float("NaN")
@classmethod
def VALIDATE_INPUTS(cls, **kwargs):
return True
# 全局实例
power_artist_loader_instance = PowerArtistLoader()
# API路由
@PromptServer.instance.routes.get("/power_artist_loader/artists")
async def get_artists(request):
"""获取画师列表API"""
try:
# 每次请求时重新加载 CSV
power_artist_loader_instance.load_artists_data()
artists_list = []
for name, data in power_artist_loader_instance.artists_data.items():
artists_list.append({
'name': name,
'keywords': data.get('keywords', ''),
'image': data.get('image', None)
})
return web.json_response({
'artists': artists_list
})
except Exception as e:
return web.json_response({
'error': str(e)
}, status=500)
@PromptServer.instance.routes.get("/power_artist_loader/preview/{image_name}")
async def get_preview_image(request):
"""获取预览图片API"""
try:
image_name = request.match_info['image_name']
images_path = os.path.join(os.path.dirname(__file__), "images")
image_path = os.path.join(images_path, image_name)
if os.path.exists(image_path):
return web.FileResponse(image_path)
else:
return web.Response(status=404)
except Exception as e:
return web.Response(status=404)
# 节点类映射
NODE_CLASS_MAPPINGS = {
"PowerArtistLoader": PowerArtistLoader
}
# 节点显示名映射
NODE_DISPLAY_NAME_MAPPINGS = {
"PowerArtistLoader": "Power Artist Loader"
}
# 导出所需的变量
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']