Skip to content

Commit ef6678a

Browse files
committed
merge dev into main
2 parents 8a12f73 + 3800e47 commit ef6678a

8 files changed

Lines changed: 337 additions & 97 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ __pycache__/
66
*.pyd
77
.DS_Store
88
.vscode/
9-
text_storage.json
9+
text_storage/*
10+
!text_storage/.gitkeep
1011
wildcards/*
1112
!wildcards/.gitkeep
1213
!wildcards/example_format.txt

README.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,27 @@ Fetches and formats headlines from any URL. Ideal for injecting real-time contex
8080
* **Safe:** Includes timeouts and error handling to prevent workflow freezing.
8181
8282
### Text Storage Nodes (Reader & Writer)
83-
A persistent "clipboard" for ComfyUI. We have split this into two separate nodes for better clarity and workflow management.
84-
* **Text Storage (Reader)**:
85-
* **Simple Interface:** Just a dropdown menu to select and output your saved text.
86-
* **Auto-Refresh:** Automatically updates the list when new text is saved via the Writer node.
87-
* **Text Storage (Writer)**:
88-
* **Dedicated Actions:** Supports `Add New (Auto Rename)`, `Overwrite Existing`, and `Delete`.
89-
* **Force Input:** Accepts text input directly from other nodes (string connection).
90-
* **Local Storage:** All data is saved safely to `text_storage.json` within the node folder.
83+
A persistent "clipboard" for ComfyUI. These nodes allow you to save and retrieve text data across different workflows or sessions. All data is securely stored in the `text_storage/` directory within the node folder.
84+
85+
#### **Text Storage (Writer)**
86+
Saves text content to a file or internal database.
87+
* **Inputs:**
88+
* `text_input`: The text content to save.
89+
* `filename_prefix`: Optional prefix for categorization (e.g., `ProjectA_`).
90+
* `save_name`: The main filename or key. Supports **Time Formatting** (e.g., `%Y-%m-%d`) and **Wildcards** (e.g., `***` for auto-incrementing 001, 002...).
91+
* `mode`:
92+
* **Add New (Auto Rename)**: Automatically avoids conflicts by renaming (e.g., `Log_2024-11-26_001.txt`).
93+
* **Overwrite Existing**: Replaces content if the name exists.
94+
* **Delete**: Removes the specified file/key.
95+
* **`storage_format` (New!)**:
96+
* `json`: Saves as a key inside the internal `text_storage.json` database.
97+
* `txt`: Saves as a standalone `.txt` file for easy external editing.
98+
99+
#### **Text Storage (Reader)**
100+
Retrieves saved text content.
101+
* **Unified List:** Automatically scans and lists both JSON keys and `.txt` files from the storage folder.
102+
* **Passthrough:** Outputs the selected text content string.
103+
* **> Important Note:** The dropdown list is generated when the node loads. If you have just saved a NEW file using the Writer node, you must **Refresh the ComfyUI Page (F5)** to see the new file appear in the Reader's list.
91104
92105
### Wildcards Processor (Dynamic Prompt Mixer)
93106

README.zh-TW.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,27 @@
8080
* **安全機制:** 內建超時與錯誤處理,防止工作流卡死。
8181
8282
### Text Storage Nodes (文字倉庫 - 讀寫分離版)
83-
ComfyUI 內部的「持久化剪貼簿」。為了提升易用性,我們將其拆分為讀取與寫入兩個專用節點。
84-
* **Text Storage (Reader / 讀取器)**:
85-
* **介面乾淨:** 僅需透過下拉選單選擇檔案,即可輸出文字內容。
86-
* **自動刷新:** 當透過寫入器存入新檔案後,列表會自動更新。
87-
* **Text Storage (Writer / 寫入器)**:
88-
* **明確操作:** 支援 `新增 (自動重新命名)`、`覆蓋現有檔案` 與 `刪除` 三種模式。
89-
* **強制輸入:** 透過連線接收來自其他節點的字串輸入 (String Input),符合自動化邏輯。
90-
* **本地儲存:** 數據保存在節點目錄下的 `text_storage.json`,安全且易於備份。
83+
ComfyUI 內部的「持久化剪貼簿」。允許您在不同的工作流或會話之間保存與讀取文字數據,所有資料皆安全儲存在節點目錄下的 `text_storage/` 資料夾中。
84+
85+
#### **Text Storage (Writer / 寫入器)**
86+
將文字內容保存到檔案或內部資料庫。
87+
* **Inputs (輸入):**
88+
* `text_input`: 要保存的文字內容。
89+
* `filename_prefix`: 可選的分類前綴 (例如 `ProjectA_`)。
90+
* `save_name`: 主要檔名或鍵值。支援 **時間格式化** (如 `%Y-%m-%d`) 與 **通配符** (如 `***` 代表自動編號 001, 002...)。
91+
* `mode`:
92+
* **Add New (Auto Rename)**: 新增模式。若檔名重複會自動更名 (例如 `Log_2024-11-26_001.txt`),避免覆蓋。
93+
* **Overwrite Existing**: 覆蓋模式。若檔名存在則直接覆蓋內容。
94+
* **Delete**: 刪除模式。移除指定的檔案或鍵值。
95+
* **`storage_format` (新功能!)**:
96+
* `json`: 作為鍵值對 (Key-Value) 儲存在內部的 `text_storage.json` 資料庫中。
97+
* `txt`: 儲存為獨立的 `.txt` 文字檔,方便外部編輯或查看。
98+
99+
#### **Text Storage (Reader / 讀取器)**
100+
讀取已保存的文字內容。
101+
* **統一列表:** 自動掃描並列出資料夾內所有的 JSON 鍵值與 `.txt` 檔案。
102+
* **直通輸出:** 輸出選定的文字內容字串。
103+
* **> 重要提示:** 下拉選單是在節點載入時生成的。如果您剛剛透過 Writer 寫入了新檔案,必須 **重新整理 ComfyUI 網頁 (F5)**,新檔案才會出現在 Reader 的列表中。
91104
92105
### Wildcards Processor (動態提示詞混合器)
93106
使用通配符語法(如 `__style__`)和隨機選擇(如 `{cat|dog}`)生成豐富的動態提示詞。此節點已進化為強大的 **7 槽混合器**。

__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
from .image_cropper import NODE_CLASS_MAPPINGS as IMAGE_CLASS_MAPPINGS
1111
from .image_cropper import NODE_DISPLAY_NAME_MAPPINGS as IMAGE_DISPLAY_NAME_MAPPINGS
1212

13+
from .mask_nodes import NODE_CLASS_MAPPINGS as MASK_CLASS_MAPPINGS
14+
from .mask_nodes import NODE_DISPLAY_NAME_MAPPINGS as MASK_DISPLAY_NAME_MAPPINGS
15+
1316
NODE_CLASS_MAPPINGS = {
1417
"AdvancedTextFilter": AdvancedTextFilter,
1518
"TextInput": TextInput,
@@ -38,4 +41,7 @@
3841
NODE_CLASS_MAPPINGS.update(IMAGE_CLASS_MAPPINGS)
3942
NODE_DISPLAY_NAME_MAPPINGS.update(IMAGE_DISPLAY_NAME_MAPPINGS)
4043

44+
NODE_CLASS_MAPPINGS.update(MASK_CLASS_MAPPINGS)
45+
NODE_DISPLAY_NAME_MAPPINGS.update(MASK_DISPLAY_NAME_MAPPINGS)
46+
4147
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']

mask_nodes.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import os
2+
import numpy as np
3+
import torch
4+
from PIL import Image, ImageOps
5+
import folder_paths
6+
7+
class TP_SaveMask:
8+
def __init__(self):
9+
self.output_dir = folder_paths.get_output_directory()
10+
self.type = "output"
11+
self.prefix_append = ""
12+
13+
@classmethod
14+
def INPUT_TYPES(s):
15+
return {
16+
"required": {
17+
"mask": ("MASK", ),
18+
"filename_prefix": ("STRING", {"default": "Mask_Output"}),
19+
},
20+
}
21+
22+
RETURN_TYPES = ()
23+
FUNCTION = "save_mask"
24+
OUTPUT_NODE = True
25+
CATEGORY = "ComfyUI Text Processor/Image"
26+
27+
def save_mask(self, mask, filename_prefix="Mask_Output"):
28+
full_output_folder, filename, counter, subfolder, filename_prefix = \
29+
folder_paths.get_save_image_path(filename_prefix, self.output_dir, mask.shape[2], mask.shape[1])
30+
31+
results = list()
32+
for batch_number, single_mask in enumerate(mask):
33+
i = 255. * single_mask.cpu().numpy()
34+
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
35+
36+
file = f"{filename}_{counter:05}_.png"
37+
img.save(os.path.join(full_output_folder, file))
38+
results.append({
39+
"filename": file,
40+
"subfolder": subfolder,
41+
"type": self.type
42+
})
43+
counter += 1
44+
45+
return { "ui": { "images": results } }
46+
47+
class TP_LoadMask:
48+
@classmethod
49+
def INPUT_TYPES(s):
50+
input_dir = folder_paths.get_input_directory()
51+
files = []
52+
53+
try:
54+
files = folder_paths.get_filename_list("input")
55+
except (KeyError, AttributeError):
56+
if os.path.exists(input_dir):
57+
supported_ext = {'.png', '.jpg', '.jpeg', '.bmp', '.webp', '.tiff'}
58+
for root, dirs, filenames in os.walk(input_dir):
59+
for filename in filenames:
60+
if os.path.splitext(filename)[1].lower() in supported_ext:
61+
filepath = os.path.join(root, filename)
62+
rel_path = os.path.relpath(filepath, input_dir)
63+
rel_path = rel_path.replace("\\", "/")
64+
files.append(rel_path)
65+
else:
66+
files = []
67+
68+
return {
69+
"required": {
70+
"image": (sorted(files), {"image_upload": True})
71+
},
72+
}
73+
74+
CATEGORY = "ComfyUI Text Processor/Image"
75+
RETURN_TYPES = ("MASK", )
76+
FUNCTION = "load_mask"
77+
78+
def load_mask(self, image):
79+
image_path = folder_paths.get_annotated_filepath(image)
80+
i = Image.open(image_path)
81+
i = ImageOps.exif_transpose(i)
82+
83+
if i.mode != 'L':
84+
i = i.convert('L')
85+
86+
image = np.array(i).astype(np.float32) / 255.0
87+
mask = torch.from_numpy(image)
88+
mask = mask.unsqueeze(0)
89+
90+
return (mask, )
91+
92+
NODE_CLASS_MAPPINGS = {
93+
"TP_SaveMask": TP_SaveMask,
94+
"TP_LoadMask": TP_LoadMask
95+
}
96+
97+
NODE_DISPLAY_NAME_MAPPINGS = {
98+
"TP_SaveMask": "Save Mask",
99+
"TP_LoadMask": "Load Mask"
100+
}

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "text_processor"
33
description = "A comprehensive suite of utility nodes for ComfyUI: Text Processing, Logic Evaluation, and Image Tools."
4-
version = "1.2.6"
4+
version = "1.3.0"
55
license = {file = "LICENSE"}
66
# classifiers = [
77
# # For OS-independent nodes (works on all operating systems)

0 commit comments

Comments
 (0)