187 lines
7.3 KiB
Markdown
187 lines
7.3 KiB
Markdown
# Save Prompt To File
|
|
## Documentation
|
|
- Class name: `SavePromptToFile`
|
|
- Category: `OneButtonPrompt`
|
|
- Output node: `True`
|
|
|
|
The SavePromptToFile node is designed to save various components of a prompt, including positive and negative aspects, into a text file. It handles the creation of a unique filename based on the prompt content or a provided prefix, ensuring the saved file is easily identifiable and organized within a specified directory.
|
|
## Input types
|
|
### Required
|
|
- **`filename_prefix`**
|
|
- An optional prefix for the filename, allowing for custom organization or identification of the file within the output directory.
|
|
- Comfy dtype: `STRING`
|
|
- Python dtype: `str`
|
|
- **`positive_prompt`**
|
|
- The main prompt text to be saved. It serves as the primary content for the file and influences the generation of the filename if no prefix is provided.
|
|
- Comfy dtype: `STRING`
|
|
- Python dtype: `str`
|
|
- **`negative_prompt`**
|
|
- The negative aspects of the prompt to be saved, providing a contrast or alternative perspective to the positive prompt.
|
|
- Comfy dtype: `STRING`
|
|
- Python dtype: `str`
|
|
### Optional
|
|
- **`prompt_g`**
|
|
- An optional granular component of the prompt, saved additionally if provided.
|
|
- Comfy dtype: `STRING`
|
|
- Python dtype: `str`
|
|
- **`prompt_l`**
|
|
- Another optional granular component of the prompt, saved if present to add more context or detail.
|
|
- Comfy dtype: `STRING`
|
|
- Python dtype: `str`
|
|
## Output types
|
|
- **`ui`**
|
|
- Indicates the completion of the file saving process, returning a simple confirmation message.
|
|
## Usage tips
|
|
- Infra type: `CPU`
|
|
- Common nodes: unknown
|
|
|
|
|
|
## Source code
|
|
```python
|
|
class SavePromptToFile:
|
|
def __init__(self):
|
|
self.output_dir = folder_paths.get_output_directory()
|
|
self.type = "output"
|
|
self.prefix_append = ""
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"filename_prefix": ("STRING", {"default": "Prompt"}),
|
|
"positive_prompt": ("STRING",{"multiline": True}),
|
|
"negative_prompt": ("STRING",{"multiline": True}),
|
|
},
|
|
"optional": {
|
|
"prompt_g": ("STRING",{"multiline": True}),
|
|
"prompt_l": ("STRING",{"multiline": True}),
|
|
},
|
|
}
|
|
|
|
OUTPUT_NODE = True
|
|
RETURN_TYPES = ()
|
|
FUNCTION = "saveprompttofile"
|
|
|
|
CATEGORY = "OneButtonPrompt"
|
|
|
|
def saveprompttofile(self, positive_prompt, prompt_g, prompt_l, negative_prompt, filename_prefix):
|
|
# Some stuff for the prefix
|
|
filename_prefix += self.prefix_append
|
|
|
|
# turns out there is some hardcoded stuff on saveimage we have to kind of repeat here
|
|
# Find the %date:yyyy-M-d% pattern using regular expression
|
|
pattern = r'%date:([^\%]+)%'
|
|
match = re.search(pattern, filename_prefix)
|
|
|
|
if match:
|
|
# Extract the date format from the match
|
|
date_format = match.group(1)
|
|
|
|
# Get the current date
|
|
current_date = datetime.now()
|
|
|
|
# convert the ComfyUI standard into Python standard format.
|
|
# What a crazy way of doing this
|
|
# first lol, I got to make sure it doesn't overlap things
|
|
date_format = date_format.replace('M', 'X')
|
|
date_format = date_format.replace('m', 'Z')
|
|
|
|
# This is so bad
|
|
|
|
# lets make it even worse, it work differently on windows than in Linux
|
|
if(platform.system() == 'Windows'):
|
|
|
|
date_format = date_format.replace('yyyy', '%Y')
|
|
date_format = date_format.replace('yy', '%#y')
|
|
date_format = date_format.replace('X', '%#m')
|
|
date_format = date_format.replace('d', '%#d')
|
|
date_format = date_format.replace('h', '%#H')
|
|
date_format = date_format.replace('Z', '%#M')
|
|
date_format = date_format.replace('s', '%#S')
|
|
else:
|
|
date_format = date_format.replace('yyyy', '%Y')
|
|
date_format = date_format.replace('yy', '%-y')
|
|
date_format = date_format.replace('X', '%-m')
|
|
date_format = date_format.replace('d', '%-d')
|
|
date_format = date_format.replace('h', '%-H')
|
|
date_format = date_format.replace('Z', '%-M')
|
|
date_format = date_format.replace('s', '%-S')
|
|
|
|
|
|
# Format the date using the extracted format
|
|
formatted_date = current_date.strftime(date_format)
|
|
|
|
# Replace the matched pattern with the formatted date
|
|
filename_prefix = re.sub(pattern, formatted_date, filename_prefix)
|
|
|
|
|
|
|
|
|
|
full_output_folder, filename_short, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.output_dir)
|
|
|
|
# make the filename, from from a to the first comma
|
|
# find the index of the first comma after "of a" or end of the prompt
|
|
if(positive_prompt.find("of a ") != -1):
|
|
start_index = positive_prompt.find("of a ") + len("of a ")
|
|
end_index = positive_prompt.find(",", start_index)
|
|
if(end_index == -1):
|
|
end_index=len(positive_prompt)
|
|
else:
|
|
start_index = 0
|
|
end_index = 128
|
|
|
|
# extract the desired substring using slicing
|
|
filename = positive_prompt[start_index:end_index]
|
|
|
|
# cleanup some unsafe things in the filename
|
|
filename = filename.replace("\"", "")
|
|
filename = filename.replace("[", "")
|
|
filename = filename.replace("|", "")
|
|
filename = filename.replace("]", "")
|
|
filename = filename.replace("<", "")
|
|
filename = filename.replace(">", "")
|
|
filename = filename.replace(":", "_")
|
|
filename = filename.replace(".", "")
|
|
filename = re.sub(r'[0-9]+', '', filename)
|
|
|
|
safe_characters = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.")
|
|
|
|
# Use regular expression to filter out any characters not in the whitelist
|
|
filename = re.sub(r"[^{}]+".format(re.escape(''.join(safe_characters))), '', filename)
|
|
|
|
|
|
if(filename==""):
|
|
filename = str(uuid.uuid4())
|
|
|
|
if(filename_prefix == ""):
|
|
# create a datetime object for the current date and time
|
|
# if there is no prefix
|
|
now = datetime.now()
|
|
filenamecomplete = now.strftime("%Y%m%d%H%M%S") + "_" + filename.replace(" ", "_").strip() + ".txt"
|
|
|
|
else:
|
|
# lol since we insert a file, the counter of the image goes up by 1.
|
|
# So we add 1 here, so the prompt file matches the image file
|
|
formatted_counter = str(counter + 1).zfill(5)
|
|
filenamecomplete = filename_short + "_" + formatted_counter + "_" + filename.replace(" ", "_").strip() + ".txt"
|
|
|
|
|
|
directoryandfilename = os.path.abspath(os.path.join(full_output_folder, filenamecomplete))
|
|
|
|
|
|
with open(directoryandfilename, 'w', encoding="utf-8") as file:
|
|
file.write("prompt: " + positive_prompt + "\n")
|
|
|
|
if(len(prompt_g) > 0):
|
|
file.write("prompt_g: " + prompt_g + "\n")
|
|
if(len(prompt_l) > 0):
|
|
file.write("prompt_l: " + prompt_l + "\n")
|
|
|
|
file.write("negative prompt: " + negative_prompt + "\n")
|
|
|
|
|
|
|
|
return ("done")
|
|
|
|
```
|