Files
AISeDam 5cd28130a0 v0.6.00
- Add RP Converter node (Ollama LLM, gemma3:12b recommended)
- Add steps_add_per_div / cfg_add_per_div to RP KSampler (SDXL)
- Add fallback inpainting for displaced persons in all detailers
- Switch RPRegionalDetailer to full-image YOLO + bbox-center region assignment
- Rename RP KSampler -> RP KSampler (SDXL), RP Regional Detailer -> RP Regional Detailer (SDXL)
- Remove RP KSampler (Z-Image / Qwen / FLUX.2)
- Remove deprecated stub files
- Update workflow files
- Update README (EN/KO/JP/CN)
2026-05-04 00:59:29 +09:00

142 lines
6.5 KiB
Python

# SPDX-License-Identifier: AGPL-3.0-or-later
#
# ComfyUI_RP_Cast
# Copyright (C) 2024-2026 ComfyUI_RP_Cast Contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# Third-party references (algorithm/pattern, not direct code copy):
# - sd-webui-regional-prompter (hako-mikan) : AGPL-3.0
# - ComfyUI-Impact-Pack (ltdrdata) : AGPL-3.0
# - ComfyUI-ZImagePowerNodes (martin-rizzo) : MIT
# - ComfyUI-WD14-Tagger (pythongosssss) : MIT
#
"""
ComfyUI_RP_Cast — Regional Prompter for ComfyUI
Version: 0.5.59
"""
import os, sys, importlib.util
_HERE = os.path.dirname(os.path.abspath(__file__))
if _HERE not in sys.path:
sys.path.insert(0, _HERE)
# ── Load node modules via absolute path (avoids package name conflicts) ────────
def _load_module(name, rel_path):
"""Load a module from a path relative to this package directory."""
abs_path = os.path.join(_HERE, rel_path)
spec = importlib.util.spec_from_file_location(
f"ComfyUI_RP_Cast.{name}", abs_path,
submodule_search_locations=[os.path.dirname(abs_path)],
)
mod = importlib.util.module_from_spec(spec)
sys.modules[f"ComfyUI_RP_Cast.{name}"] = mod
# Also register under short name for cross-module imports
sys.modules[name] = mod
spec.loader.exec_module(mod)
return mod
# Load shared utilities first
_shared = _load_module("nodes._shared", "nodes/_shared.py")
_common = _load_module("nodes._rp_txt2img_common", "nodes/_rp_txt2img_common.py")
_pp = _load_module("nodes.node_rp_prompt_parser", "nodes/node_rp_prompt_parser.py")
_ks = _load_module("nodes.node_rp_ksampler", "nodes/node_rp_ksampler.py")
_det = _load_module("nodes.node_rp_detailer", "nodes/node_rp_detailer.py")
_det_zi = _load_module("nodes.node_rp_detailer_zimage", "nodes/node_rp_detailer_zimage.py")
_conv = _load_module("nodes.node_rp_converter", "nodes/node_rp_converter.py")
_det_qw = _load_module("nodes.node_rp_detailer_qwen", "nodes/node_rp_detailer_qwen.py")
_oai = _load_module("nodes.node_rp_txt2img_openai", "nodes/node_rp_txt2img_openai.py")
_gem = _load_module("nodes.node_rp_txt2img_gemini", "nodes/node_rp_txt2img_gemini.py")
_grok = _load_module("nodes.node_rp_txt2img_grok", "nodes/node_rp_txt2img_grok.py")
# ── Node class references ──────────────────────────────────────────────────────
RPPromptParser = _pp._RPPromptParser if hasattr(_pp, "_RPPromptParser") else _pp.RPPromptParser
RPRatioParser = _pp.RPRatioParser
RPKSampler = _ks.RPKSampler
RPRegionalDetailer = _det.RPRegionalDetailer
RPRegionalDetailerZImage = _det_zi.RPRegionalDetailerZImage
RPConverter = _conv.RPConverter
RPRegionalDetailerQwen = _det_qw.RPRegionalDetailerQwen
# For test compatibility
_auto_aratios = _pp._auto_aratios
_count_addcol = _pp._count_addcol
# ── Registration ──────────────────────────────────────────────────────────────
_VERSION = "0.5.59"
NODE_CLASS_MAPPINGS = {
"RPPromptParser": RPPromptParser,
"RPRatioParser": RPRatioParser,
"RPKSampler": RPKSampler,
"RPRegionalDetailer": RPRegionalDetailer,
"RPRegionalDetailerZImage": RPRegionalDetailerZImage,
"RPConverter": RPConverter,
"RPRegionalDetailerQwen": RPRegionalDetailerQwen,
"RPTxt2ImgOpenAI": _oai.RPTxt2ImgOpenAI,
"RPTxt2ImgGemini": _gem.RPTxt2ImgGemini,
"RPTxt2ImgGrok": _grok.RPTxt2ImgGrok,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"RPPromptParser": "RP Prompt Parser",
"RPRatioParser": "RP Ratio Parser",
"RPKSampler": "RP KSampler (SDXL)",
"RPRegionalDetailer": "RP Regional Detailer (SDXL)",
"RPRegionalDetailerZImage": "RP Regional Detailer (Z-Image)",
"RPConverter": "RP Converter",
"RPRegionalDetailerQwen": "RP Regional Detailer (Qwen)",
"RPTxt2ImgOpenAI": "RP Txt2Img (OpenAI)",
"RPTxt2ImgGemini": "RP Txt2Img (Gemini)",
"RPTxt2ImgGrok": "RP Txt2Img (Grok)",
}
print(f"[ComfyUI_RP_Cast v{_VERSION}] {len(NODE_CLASS_MAPPINGS)} nodes registered: "
f"{list(NODE_CLASS_MAPPINGS.keys())}")
WEB_DIRECTORY = "./web"
# ── Settings API route ────────────────────────────────────────────────────────
try:
from server import PromptServer as _PromptServer
from aiohttp import web as _web
import json as _json
@_PromptServer.instance.routes.get("/rp_cast/settings")
async def _rp_cast_settings(request):
"""Return RP Cast settings stored in ComfyUI settings file."""
setting_key = "ComfyUI-RP-Cast.Configuration.openai_api_key"
api_key = ""
try:
settings_path = os.path.join(
os.path.dirname(os.path.dirname(_HERE)),
"user", "default", "comfy.settings.json"
)
if os.path.exists(settings_path):
with open(settings_path, "r", encoding="utf-8") as f:
all_settings = _json.load(f)
api_key = all_settings.get(setting_key, "")
except Exception as _se:
print(f"[ComfyUI_RP_Cast] Failed to read settings: {_se}")
return _web.Response(
text=_json.dumps({setting_key: api_key}),
content_type="application/json"
)
print(f"[ComfyUI_RP_Cast] Route registered: /rp_cast/settings")
except Exception as _e:
print(f"[ComfyUI_RP_Cast] Route registration failed: {_e}")
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]