添加DD TXT文件合并器节点

This commit is contained in:
Dontdrunk
2025-09-21 14:52:35 +08:00
parent 8c21b385c9
commit 0595a598e9
7 changed files with 279 additions and 4 deletions
+126
View File
@@ -0,0 +1,126 @@
# ComfyUI-DD-Nodes Developer Guide
## Architecture Overview
This is a **ComfyUI extension** with hybrid Python/JavaScript architecture:
- **Backend**: Python nodes in `/node/` (image processing, AI workflows)
- **Frontend**: JavaScript extensions in `/extensions/` (UI enhancements, animations, APIs)
- **Localization**: Bilingual support via `/locales/zh/` and `/locales/en/`
## Key Development Patterns
### Adding New Nodes
1. Create Python class in `/node/` with ComfyUI conventions:
```python
class YourNode:
@classmethod
def INPUT_TYPES(s):
return {"required": {"input": ("TYPE",)}}
RETURN_TYPES = ("OUTPUT_TYPE",)
FUNCTION = "process"
CATEGORY = "🍺DD系列节点"
```
2. Export in `NODE_CLASS_MAPPINGS = {"DD-YourNode": YourNode}`
3. Import in `__init__.py` and add to main `NODE_CLASS_MAPPINGS`
4. Add Chinese translations to `locales/zh/nodeDefs.json`
### Frontend Extensions
Create extension in `/extensions/YourExt/`:
```javascript
import { app } from "/scripts/app.js";
app.registerExtension({
name: "ComfyUI.YourExtension",
setup() {
// Initialization code
},
beforeRegisterNodeDef(nodeType, nodeData, app) {
// Hook into node creation
}
});
```
### Adding API Endpoints
In Python modules, use ComfyUI's PromptServer:
```python
from server import PromptServer
@PromptServer.instance.routes.post("/your_api/endpoint")
async def your_handler(request):
return web.json_response({"success": True})
```
## Critical Conventions
### Canvas Monkey-Patching
When modifying ComfyUI's canvas behavior, **always preserve original methods**:
```javascript
const originalMethod = app.canvas.originalMethod;
app.canvas.originalMethod = function(...args) {
// Your enhancement
return originalMethod?.call(this, ...args);
};
```
### Settings Integration
Use ComfyUI's built-in settings system:
```javascript
app.extensionManager.setting.get("YourExt.setting") ?? defaultValue
app.extensionManager.setting.onChange("YourExt.setting", callback)
```
### Theme Architecture
Themes must implement interface: `{init, applyTheme, flipCoin, cleanup, name}`
Register via: `registerTheme('theme-id', themeModule)`
## Performance Patterns
### Spatial Optimization
For canvas operations affecting many nodes, use spatial partitioning (see `StaticCircuitBoardStyle.js`):
- Build spatial grid index for O(1) lookups
- Use Bresenham line algorithm for collision detection
- Dynamic grid sizing based on node count
### Lazy Loading
Extensions use singleton patterns:
```javascript
function getOrCreateInstance() {
if (!app.canvas._yourInstance) {
app.canvas._yourInstance = new YourClass();
}
return app.canvas._yourInstance;
}
```
## File Structure Conventions
```
/node/ # Python backend nodes
/extensions/ # Frontend JavaScript modules
/YourExt/
YourExtExt.js # Extension entry (imported in index.js)
YourExtCore.js # Core functionality
/styles/ # UI styling and utilities
/locales/zh/ # Chinese translations
nodeDefs.json # Node translations
main.json # UI translations
```
## Development Workflow
1. **No build system** - Direct ES6 modules, hot-reload friendly
2. **Testing**: Restart ComfyUI to test Python changes, refresh for JS changes
3. **Dependencies**: Add to `requirements.txt`, use npm-style imports for JS
4. **Debugging**: Use browser DevTools for frontend, Python print/logging for backend
## Integration Points
- Node widgets auto-added via `beforeRegisterNodeDef` hooks
- Settings persist via ComfyUI's storage system
- API calls use `/scripts/api.js` from ComfyUI core
- Internationalization follows ComfyUI's i18n system
- Extension loading via `WEB_DIRECTORY = "extensions"` in `__init__.py`
When adding features, follow existing patterns in `/extensions/Prompt_Manager/` (API integration) or `/extensions/Online_Animation/` (canvas enhancement) as reference implementations.
+8 -3
View File
@@ -31,6 +31,9 @@
| **DD Image Size Limiter** | Smart image size limiter ensuring images are within specified maximum and minimum size ranges, preventing memory overflow and performance issues | ![Image Size Limiter Interface](https://github.com/user-attachments/assets/d2fac125-fad3-4f51-9b91-39d0be4c7753) |
| **DD Switcher Series** | Includes condition switcher, latent switcher, model switcher and other switching nodes, simplifying workflows and improving processing flexibility | ![Switcher Series Interface](https://github.com/user-attachments/assets/54690c0c-3627-4970-9bc0-ef58ca4be2f7) |
| **DD Video First Last Frame** | Professional video frame extraction tool that can precisely extract the first and last frames of videos, providing convenience for video processing workflows | ![Video First Last Frame](https://github.com/user-attachments/assets/243c4809-8c83-43a3-9c2b-768f16644ded) |
| **DD Image Splitter** | Intelligent image splitting tool that supports splitting images into multiple parts by custom ratios. Supports horizontal (left-right) or vertical (top-bottom) splitting, supports unequal ratio splitting (like 2:1:3), and can output specified split results | ![Image Splitter Interface](To be added) |
| **DD Aspect Ratio Selector** | Intelligent aspect ratio selection tool that provides recommended resolutions for different AI models (such as Qwen-image, Wan2.2). Supports three ratio categories: landscape, portrait, and square, automatically providing the most suitable size parameters for the model | ![Aspect Ratio Selector Interface](To be added) |
| **DD TXT File Merger** | Powerful text file merging tool that can recursively scan all TXT files in specified folders and subfolders, merging them into a single text content. Automatically adds file path identifiers and supports multiple text encoding formats | ![TXT File Merger Interface](To be added) |
## 🎯 Extension Functions Overview
@@ -62,9 +65,11 @@ This extension now supports ComfyUI's native internationalization (i18n) system
## 📈 Version History
### Latest Version
- **v2.6.0** (2025-07-06)
- 🔧 Attempted to fix multi-system compatibility bugs in interface layout panel
- ➕ Added video first and last frame output node
- **v3.1.0** (2025-09-21)
- Added DD TXT File Merger node, supports recursive scanning of all TXT files in folders and subfolders and merging them into single text content
- **v3.0.0** (2025-09-05)
- Added DD Image Splitter node, supports splitting images by custom ratios and outputting specified parts
### Important Updates
- **v2.5.1** (2025-07-02)
+7 -1
View File
@@ -41,6 +41,9 @@
| **DD 限制图像大小** | 智能图像尺寸限制器,确保图像在指定的最大和最小尺寸范围内,防止内存溢出和性能问题 | ![限制图像大小界面](https://github.com/user-attachments/assets/d2fac125-fad3-4f51-9b91-39d0be4c7753) |
| **DD 切换器系列** | 包含条件切换器、Latent切换器、模型切换器等多种切换节点,简化工作流程,提高处理灵活性 | ![切换器系列界面](https://github.com/user-attachments/assets/54690c0c-3627-4970-9bc0-ef58ca4be2f7) |
| **DD 视频首尾帧输出** | 专业的视频帧提取工具,可以精确提取视频的第一帧和最后一帧,为视频处理工作流提供便利 | ![首尾](https://github.com/user-attachments/assets/243c4809-8c83-43a3-9c2b-768f16644ded) |
| **DD 图像切分器** | 智能图像切分工具,支持按自定义比例将图像切分为多个部分。可选择左右切分或上下切分,支持不等比例切分(如2:1:3),并可输出指定位置的切分结果 | ![图像切分器界面](待添加) |
| **DD 比例选择器** | 智能的宽高比选择工具,针对不同AI模型(如Qwen-image、Wan2.2)提供推荐分辨率。支持横屏、竖屏、方形三种比例类别,自动提供最适合模型的尺寸参数 | ![比例选择器界面](待添加) |
| **DD TXT文件合并器** | 强大的文本文件合并工具,可以递归扫描指定文件夹及其子文件夹中的所有TXT文件,并将其合并为单个文本内容。自动添加文件路径标识,支持多种文本编码格式 | ![TXT合并器界面](待添加) |
## 🔧 安装方法
@@ -64,8 +67,11 @@
## 📈 版本历史
### 最新版本
- **v3.1.0**(2025-09-21)
- 添加DD TXT文件合并器节点,支持递归扫描文件夹及子文件夹中的所有TXT文件并合并为单个文本内容
- **v3.0.0**(2025-09-05)
- 添加比例切分器节点
- 添加DD 图像切分器节点,支持按自定义比例切分图像并输出指定部分
- **v2.9.1**(2025-09-04)
- 删除DD采样器节点,它已经不适用最新的CommyUI了
+3
View File
@@ -12,6 +12,7 @@ from .node.condition_switcher import NODE_CLASS_MAPPINGS as CONDITION_SWITCHER_N
from .node.latent_switcher import NODE_CLASS_MAPPINGS as LATENT_SWITCHER_NODES
from .node.image_stroke import NODE_CLASS_MAPPINGS as IMAGE_STROKE_NODES
from .node.image_splitter import NODE_CLASS_MAPPINGS as IMAGE_SPLITTER_NODES
from .node.txt_file_merger import NODE_CLASS_MAPPINGS as TXT_MERGER_NODES
# 导入Qwen-MT翻译节点
from .extensions.Qwen_MT.nodes import NODE_CLASS_MAPPINGS as QWEN_MT_NODES
@@ -39,6 +40,7 @@ NODE_CLASS_MAPPINGS = {
**LATENT_SWITCHER_NODES,
**IMAGE_STROKE_NODES,
**IMAGE_SPLITTER_NODES,
**TXT_MERGER_NODES,
**QWEN_MT_NODES,
**ASPECT_RATIO_NODES,
}
@@ -59,6 +61,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"DD-LatentSwitcher": "DD Latent Switcher",
"DD-ImageStroke": "DD Image Stroke",
"DD-ImageSplitter": "DD Image Splitter",
"DD-TxtFileMerger": "DD TXT File Merger",
"DD-QwenMTTranslator": "DD Qwen-MT",
"DD-AspectRatioSelector": "DD Aspect Ratio Selector",
}
+16
View File
@@ -382,5 +382,21 @@
"tooltip": "Extracted single frame image"
}
}
},
"DD-TxtFileMerger": {
"display_name": "DD TXT File Merger",
"description": "Merge all TXT files from a folder and its subfolders into a single text content",
"inputs": {
"input_folder": {
"name": "Input Folder",
"tooltip": "Folder path containing TXT files, will recursively scan all subfolders"
}
},
"outputs": {
"0": {
"name": "Merged Text",
"tooltip": "Complete merged text content with file path identifiers"
}
}
}
}
+16
View File
@@ -410,5 +410,21 @@
"tooltip": "输出的图像高度"
}
}
},
"DD-TxtFileMerger": {
"display_name": "DD TXT文件合并器",
"description": "将指定文件夹及其子文件夹中的所有TXT文件合并成一个文本内容",
"inputs": {
"input_folder": {
"name": "输入文件夹",
"tooltip": "包含TXT文件的文件夹路径,将递归扫描所有子文件夹"
}
},
"outputs": {
"0": {
"name": "合并文本",
"tooltip": "合并后的完整文本内容,包含文件路径标识"
}
}
}
}
+103
View File
@@ -0,0 +1,103 @@
import os
from pathlib import Path
class DDTxtFileMerger:
"""
DD TXT文件合并器
将指定文件夹及其子文件夹中的所有TXT文件合并成一个文本内容
"""
def __init__(self):
pass
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"input_folder": ("STRING", {
"default": "",
"multiline": False,
"placeholder": "输入文件夹路径,例如: C:\\texts"
}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("merged_text",)
FUNCTION = "merge_txt_files"
CATEGORY = "🍺DD系列节点/文本处理"
def merge_txt_files(self, input_folder):
"""
合并文件夹中的所有TXT文件,返回合并后的文本内容
"""
try:
# 验证输入文件夹
if not input_folder or not os.path.exists(input_folder):
return (f"错误:输入文件夹不存在: {input_folder}",)
# 递归查找所有txt文件
txt_files = []
for root, dirs, files in os.walk(input_folder):
for file in files:
if file.lower().endswith('.txt'):
txt_files.append(os.path.join(root, file))
if not txt_files:
return (f"警告:在文件夹 {input_folder} 中未找到任何TXT文件",)
# 按路径排序,确保合并顺序一致
txt_files.sort()
# 合并文件内容
merged_content = []
processed_files = 0
for txt_file in txt_files:
try:
# 尝试以UTF-8编码读取文件,失败时尝试其他编码
content = None
for encoding in ['utf-8', 'gbk', 'gb2312', 'utf-8-sig']:
try:
with open(txt_file, 'r', encoding=encoding, errors='ignore') as f:
content = f.read().strip()
break
except UnicodeDecodeError:
continue
if content: # 只处理非空文件
# 获取相对于输入文件夹的相对路径
relative_path = os.path.relpath(txt_file, input_folder)
merged_content.append(f"=== {relative_path} ===")
merged_content.append(content)
merged_content.append("") # 空行分隔
processed_files += 1
except Exception as e:
print(f"警告:无法读取文件 {txt_file}: {str(e)}")
continue
if not merged_content:
return (f"错误:所有TXT文件都为空或无法读取",)
# 合并所有内容为一个字符串
final_text = '\n'.join(merged_content)
success_msg = f"成功合并 {processed_files} 个TXT文件"
print(success_msg)
return (final_text,)
except Exception as e:
return (f"错误:处理过程中发生异常: {str(e)}",)
# 导出节点映射
NODE_CLASS_MAPPINGS = {
"DD-TxtFileMerger": DDTxtFileMerger,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"DD-TxtFileMerger": "DD TXT File Merger",
}