127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
"""
|
|
Find/Replace Pairs Node
|
|
Creates a collection of find/replace pairs with dynamic inputs.
|
|
"""
|
|
|
|
import json
|
|
from server import PromptServer
|
|
from aiohttp import web
|
|
|
|
|
|
class FindReplacePairs:
|
|
"""
|
|
A node that creates an arbitrary number of find/replace pairs.
|
|
Pairs are shown/hidden dynamically via UI button.
|
|
"""
|
|
|
|
MAX_PAIRS = 80
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
"""
|
|
Define all possible pair inputs. JS will show/hide based on pair count.
|
|
"""
|
|
inputs = {
|
|
"required": {},
|
|
"optional": {},
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID",
|
|
}
|
|
}
|
|
|
|
# Define all possible pairs - JS will control visibility
|
|
for i in range(1, cls.MAX_PAIRS + 1):
|
|
inputs["optional"][f"find_{i}"] = ("STRING", {
|
|
"default": "",
|
|
"multiline": False,
|
|
})
|
|
inputs["optional"][f"replace_{i}"] = ("STRING", {
|
|
"default": "",
|
|
"multiline": False,
|
|
})
|
|
|
|
return inputs
|
|
|
|
RETURN_TYPES = ("FR_PAIRS", "STRING", "STRING",)
|
|
RETURN_NAMES = ("pairs", "json", "csv",)
|
|
OUTPUT_TOOLTIPS = (
|
|
"Find/Replace pairs object for use with TextReplacer node",
|
|
"JSON representation of the pairs",
|
|
"CSV representation of the pairs (find,replace per line)",
|
|
)
|
|
|
|
FUNCTION = "create_pairs"
|
|
CATEGORY = "text/replace"
|
|
DESCRIPTION = "Creates a collection of find/replace pairs that can be used with the TextReplacer node."
|
|
|
|
def create_pairs(self, unique_id=None, **kwargs):
|
|
"""
|
|
Create the find/replace pairs collection.
|
|
|
|
Args:
|
|
unique_id: Node's unique ID
|
|
**kwargs: Dynamic find_N, replace_N values
|
|
|
|
Returns:
|
|
Tuple of (pairs_dict, json_string, csv_string)
|
|
"""
|
|
pairs = []
|
|
|
|
# Collect all pairs from kwargs (find_1, replace_1, find_2, replace_2, etc.)
|
|
pair_indices = set()
|
|
for key in kwargs:
|
|
if key.startswith("find_") or key.startswith("replace_"):
|
|
try:
|
|
idx = int(key.split("_")[1])
|
|
pair_indices.add(idx)
|
|
except (ValueError, IndexError):
|
|
pass
|
|
|
|
for i in sorted(pair_indices):
|
|
find_value = kwargs.get(f"find_{i}", "")
|
|
replace_value = kwargs.get(f"replace_{i}", "")
|
|
|
|
# Only add non-empty find patterns
|
|
if find_value:
|
|
pairs.append({
|
|
"find": find_value,
|
|
"replace": replace_value,
|
|
"index": i
|
|
})
|
|
|
|
# Create the pairs object
|
|
pairs_obj = {
|
|
"pairs": pairs,
|
|
"count": len(pairs),
|
|
"source_node": unique_id
|
|
}
|
|
|
|
# Create JSON output
|
|
json_output = json.dumps(pairs, indent=2)
|
|
|
|
# Create CSV output (find,replace per line)
|
|
csv_lines = []
|
|
for pair in pairs:
|
|
# Escape commas and quotes in values for CSV
|
|
find_escaped = pair["find"].replace('"', '""')
|
|
replace_escaped = pair["replace"].replace('"', '""')
|
|
if ',' in find_escaped or '"' in find_escaped:
|
|
find_escaped = f'"{find_escaped}"'
|
|
if ',' in replace_escaped or '"' in replace_escaped:
|
|
replace_escaped = f'"{replace_escaped}"'
|
|
csv_lines.append(f"{find_escaped},{replace_escaped}")
|
|
csv_output = "\n".join(csv_lines)
|
|
|
|
return (pairs_obj, json_output, csv_output)
|
|
|
|
@classmethod
|
|
def IS_CHANGED(cls, **kwargs):
|
|
"""Force re-evaluation when inputs change."""
|
|
return hash(str(kwargs))
|
|
|
|
|
|
# API route to get node info (optional, for debugging)
|
|
@PromptServer.instance.routes.get("/multi_replace/info")
|
|
async def get_info(request):
|
|
return web.json_response({"status": "ok", "name": "multi-replace"})
|