Merge pull request #1 from TKRLAB/dev

Dev
This commit is contained in:
TKRLAB
2024-12-22 13:40:55 +02:00
committed by GitHub
8 changed files with 138 additions and 83 deletions
+99 -62
View File
@@ -2,108 +2,145 @@ import json
import os
import folder_paths
from collections import OrderedDict
import random
# Define a default boolean parameter for input
BOOLEAN = ("BOOLEAN", {"default": False})
class ComfyUI_Prompt_JSON:
def __init__(self):
# Define the folder and file paths for storing prompts
# Define the folder for storing prompts
self.prompt_list_folder = os.path.join(folder_paths.base_path, "Prompt")
self.json_path = os.path.join(self.prompt_list_folder, "list.json")
# Ensure the necessary files and directories exist
self.ensure_json_file_exists()
# Load the existing data from the JSON file
self.data = self.load_json()
def ensure_json_file_exists(self):
"""Ensure the prompt directory and JSON file exist. If not, create them."""
# Ensure the folder exists
if not os.path.exists(self.prompt_list_folder):
os.makedirs(self.prompt_list_folder, exist_ok=True)
if not os.path.exists(self.json_path):
with open(self.json_path, 'w', encoding='utf-8') as file:
json.dump({}, file, ensure_ascii=False, indent=4)
def load_json(self):
"""Load data from the JSON file into an OrderedDict."""
with open(self.json_path, 'r', encoding='utf-8') as file:
def load_json(self, file_path):
"""Load data from the specified JSON file into an OrderedDict."""
if not os.path.exists(file_path):
return OrderedDict()
with open(file_path, 'r', encoding='utf-8') as file:
return json.load(file, object_pairs_hook=OrderedDict) or OrderedDict()
def save_json(self):
"""Save the current data to the JSON file."""
with open(self.json_path, 'w', encoding='utf-8') as file:
json.dump(self.data, file, ensure_ascii=False, indent=4)
def save_json(self, file_path, data):
"""Save data to the specified JSON file."""
with open(file_path, 'w', encoding='utf-8') as file:
json.dump(data, file, ensure_ascii=False, indent=4)
@classmethod
def INPUT_TYPES(cls):
"""Define the input types for the node interface."""
"""
Define the input types for the node interface.
- 'Prompt List': A dropdown to select existing prompts or create a new one.
- 'New List Name': A string input for creating a new list (used when creating a new list).
- 'Random': A boolean to enable/disable random prompt selection.
- 'Overwrite': A boolean to allow overwriting an existing prompt.
- 'Console Log': A boolean to enable logging to the console.
- 'Prompt Name': A string for naming the current prompt.
- 'Positive Prompt': Multiline text for the positive part of the prompt.
- 'Negative Prompt': Multiline text for the negative part of the prompt.
"""
instance = cls()
items = list(instance.data.keys())
# Include existing JSON files along with the option to create a "New List"
prompt_files = ["New List"] + [f for f in os.listdir(instance.prompt_list_folder) if f.endswith('.json')]
return {
"required": {
"Prompt Name": ("STRING", {"multiline": False}),
"Prompt List": (prompt_files, ),
"New List Name": ("STRING", {"multiline": False}),
"Random": BOOLEAN,
"Overwrite": BOOLEAN,
"Console log": BOOLEAN,
"Console Log": BOOLEAN,
"Prompt Name": ("STRING", {"multiline": False}),
"Positive Prompt": ("STRING", {"multiline": True}),
"Negative Prompt": ("STRING", {"multiline": True}),
}
}
# Define return types for the process function
RETURN_TYPES = ("STRING", "STRING")
RETURN_NAMES = ("positive", "negative")
RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("positive", "negative", "full list")
FUNCTION = "process"
CATEGORY = "prompt"
@classmethod
def get_prompt_list(cls):
"""Retrieve a list of all prompt names in the data."""
instance = cls()
return list(instance.data.keys())
def process(self, **kwargs):
"""
Process and update prompts.
- Adds or updates a prompt based on the provided input.
- Prints prompt information if 'Console log' is enabled.
Process prompts:
- Load the selected prompt list.
- Optionally select a random prompt from the list.
- Return the positive and negative prompts, as well as the full list.
"""
prompt_list_name = kwargs.get("Prompt List", "").strip()
new_list_name = kwargs.get("New List Name", "").strip()
random_selection = kwargs.get("Random", False)
overwrite = kwargs.get("Overwrite", False)
console_log = kwargs.get("Console Log", False)
prompt_name = kwargs.get("Prompt Name", "").strip()
positive_prompt = kwargs.get("Positive Prompt", "").strip()
negative_prompt = kwargs.get("Negative Prompt", None)
overwrite = kwargs.get("Overwrite", True)
console_log = kwargs.get("Console log", True)
negative_prompt = kwargs.get("Negative Prompt", "").strip()
# Ensure the prompt name is not empty
if not prompt_name:
raise ValueError("'Prompt Name' is required and cannot be empty.")
# Handle "New List" option: Create a new list if selected
if prompt_list_name == "New List":
if not new_list_name:
raise ValueError("'New List Name' is required when creating a new list.")
prompt_list_name = new_list_name + ".json"
# Check if the prompt already exists
if prompt_name in self.data:
# If overwrite is enabled, update the existing prompt
if overwrite:
if positive_prompt:
self.data[prompt_name]["positive"] = positive_prompt
if negative_prompt is not None:
self.data[prompt_name]["negative"] = negative_prompt
# Construct the file path for the selected or new prompt list
prompt_list_path = os.path.join(self.prompt_list_folder, prompt_list_name)
data = self.load_json(prompt_list_path)
# Handle random selection of a prompt from the list
if random_selection:
if not data:
raise ValueError("The selected prompt list is empty or invalid.")
# Choose a random prompt name and fetch its details
prompt_name = random.choice(list(data.keys()))
positive_prompt = data[prompt_name]["positive"]
negative_prompt = data[prompt_name]["negative"]
else:
# For new prompts, 'Positive Prompt' is required
if not positive_prompt:
raise ValueError("'Positive Prompt' is required when adding a new prompt.")
# Create a new prompt entry
self.data[prompt_name] = OrderedDict([
("positive", positive_prompt),
("negative", negative_prompt if negative_prompt is not None else "")
])
# Validate required fields for manual input
if not prompt_name:
raise ValueError("'Prompt Name' is required when Random is not enabled.")
if prompt_name in data:
if overwrite:
# Overwrite existing positive/negative prompts if allowed
if positive_prompt:
data[prompt_name]["positive"] = positive_prompt
if negative_prompt or not data[prompt_name]["negative"]:
data[prompt_name]["negative"] = negative_prompt
else:
# Load existing prompt details
positive_prompt = data[prompt_name]["positive"]
negative_prompt = data[prompt_name]["negative"]
else:
# Add a new prompt to the list
if not positive_prompt:
raise ValueError("'Positive Prompt' is required when adding a new prompt.")
data[prompt_name] = OrderedDict([
("positive", positive_prompt),
("negative", negative_prompt),
])
# Optionally log the prompt details to the console
if console_log:
print(f'POSITIVE: {self.data[prompt_name]["positive"]}\n')
print(f'NEGATIVE: {self.data[prompt_name]["negative"]}')
import shutil
terminal_width = shutil.get_terminal_size((80, 20)).columns
# Save changes to the JSON file
self.save_json()
return (self.data[prompt_name]["positive"], self.data[prompt_name]["negative"])
# Function to format multiline text with a background color
def format_with_bg_multiline(text, color_code):
lines = [text[i:i + terminal_width] for i in range(0, len(text), terminal_width)]
return "\n".join(f"\033[1;{color_code}m{line.ljust(terminal_width)}\033[0;0m" for line in lines)
# Log formatted details
print(format_with_bg_multiline(f"{prompt_name} from {prompt_list_name}", "40;37"))
print(format_with_bg_multiline(f"POSITIVE: {positive_prompt}", "40;32"))
print(format_with_bg_multiline(f"NEGATIVE: {negative_prompt}", "40;31"))
# Save the updated list back to the file
self.save_json(prompt_list_path, data)
# Return the processed positive prompt, negative prompt, and full list as JSON
full_list = json.dumps(data, ensure_ascii=False, indent=4)
return positive_prompt, negative_prompt, full_list
@classmethod
def IS_CHANGED(cls, *args, **kwargs):
+38 -20
View File
@@ -1,13 +1,14 @@
# ComfyUI Custom Node: Prompt List JSON
This repository provides a custom node for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) that allows managing positive and negative prompts in a structured JSON format. The node supports adding, updating, and logging prompts, ensuring seamless integration into your workflow.
This repository provides a custom node for [ComfyUI](https://github.com/comfyanonymous/ComfyUI) that allows managing positive and negative prompts in a structured JSON format. The node supports creating new prompt lists, random prompt selection, and logging prompt details to the console for seamless integration into your workflow.
## Features
- 📂 **JSON-based prompt management**: Prompts are stored in a single `list.json` file for easy editing and retrieval.
- 🔄 **Add or update prompts**: Supports both creating new prompts and overwriting existing ones.
- 🖥️ **Console logging**: Optionally logs prompt details for debugging or verification.
- 🛠️ **Automatic file management**: Creates necessary directories and files automatically if they do not exist.
- 📂 **JSON-based prompt management**: Prompts are stored in individual JSON files for easy editing and retrieval.
- 🔄 **Add or update prompts**: Supports creating new prompt lists, updating existing prompts, and overwriting as needed.
- 🎲 **Random prompt selection**: Choose a random prompt from an existing list with ease.
- 🖥️ **Console logging**: Optionally logs prompt details with formatted outputs for debugging or verification.
- 🛠️ **Automatic file management**: Ensures required directories and files are created automatically.
## Installation
@@ -16,44 +17,56 @@ This repository provides a custom node for [ComfyUI](https://github.com/comfyano
git clone https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON.git
```
2. Restart ComfyUI to load the custom node.
#### Alt method
1. Install from ComfyUI manager
#### Alternative Method
1. Install using the ComfyUI manager.
![ComfyUI manager](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/manager.png)
## Usage
![node in menu](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_in_menu.png)
![Node in menu](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_in_menu.png)
### Node Inputs
- **Prompt List**: Select an existing prompt list or create a new one.
- **New List Name**: Specify the name for a new list (used when creating a new list).
- **Prompt Name** (required): A unique name for the prompt.
- **Positive Prompt** (required for new prompts): The positive description of the prompt.
- **Negative Prompt** (optional): The negative description of the prompt.
- **Random** (boolean, default `False`): Enable random selection of prompts from the list.
- **Overwrite** (boolean, default `False`): Whether to overwrite an existing prompt with the same name.
- **Console log** (boolean, default `False`): Prints prompt details to the console for debugging.
- **Console Log** (boolean, default `False`): Prints prompt details to the console for debugging.
### Node Outputs
- **Positive Prompt**: The saved or retrieved positive prompt.
- **Negative Prompt**: The saved or retrieved negative prompt.
- **Full List**: The entire prompt list as a JSON string.
### Example Workflow
1. Add or update a prompt with the following inputs:
- **Prompt Name**: `SunsetScene`
- **Positive Prompt**: `A breathtaking sunset over the mountains`
- **Negative Prompt**: `Low quality, blurry`
- **Prompt List**: `test.json`
- **New List Name**: `test`
- **Prompt Name**: `girl on helmet`
- **Positive Prompt**: `concept art Girl in black thin, oily latex, black motorcycle helmet, black glass on helmet, pours a bucket of yellow paint on himself, paint dripping down his body, yellow silk long scarf, sexy, dynamics. Black mirrors in the background, reflections. digital artwork, illustrative, painterly, matte painting, highly detailed`
- **Negative Prompt**: `photo, photorealistic, realism, ugly`
- **Overwrite**: `True`
- **Console log**: `True`
- **Console Log**: `True`
- **Random**: `True`
![node](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node.png)
![Node](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node.png)
![Node_prev_list](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_prev_list.png)
2. The prompt will be saved to the JSON file, and its details will appear in the console if logging is enabled.
2. The prompt will be saved to the specified JSON file, and its details will appear in the console if logging is enabled.
![log](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/log.png)
### File Structure
Prompts are stored in `list.json` in the following format:
Prompts are stored in individual JSON files in the following format:
```json
{
"SunsetScene": {
@@ -70,13 +83,16 @@ You can also use this node programmatically. Here's an example:
from your_module import ComfyUI_Prompt_JSON
manager = ComfyUI_Prompt_JSON()
positive, negative = manager.process(
positive, negative, full_list = manager.process(
**{
"Prompt List": "New List",
"New List Name": "NaturePrompts",
"Prompt Name": "SunsetScene",
"Positive Prompt": "A breathtaking sunset over the mountains",
"Negative Prompt": "Low quality, blurry",
"Random": False,
"Overwrite": True,
"Console log": True
"Console Log": True
}
)
```
@@ -84,9 +100,11 @@ positive, negative = manager.process(
### Error Handling
- Raises a `ValueError` if a required field (e.g., `Prompt Name` or `Positive Prompt`) is missing.
- Displays detailed error messages for debugging in the console.
![error prompt name](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_err1.png)
![error positive prompt](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_err2.png)
![Error prompt name](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_err1.png)
![Error positive prompt](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_err2.png)
![Error New List Name](https://github.com/TKRLAB/ComfyUI_Prompt_List_JSON/blob/master/images/node_err3.png)
## License
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "comfyui_prompt_list_json"
description = "ComfyUI JSON-based prompt management tool."
version = "1.0.0"
version = "1.2.0"
license = { file = "LICENSE" }
[project.urls]