Changed node behavior to support text file uploads.

This commit is contained in:
Ricky Sekulich
2025-11-02 15:33:26 -06:00
parent 58f4af4d11
commit c8d369f52c
6 changed files with 127 additions and 24 deletions
+8 -1
View File
@@ -1 +1,8 @@
from .nodes import *
# Import our node classes
from .nodes import *
# This tells ComfyUI to look for a 'js' folder in our directory
WEB_DIRECTORY = "js"
# Tell ComfyUI about all the parts of our node
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
Binary file not shown.
Binary file not shown.
View File
+101
View File
@@ -0,0 +1,101 @@
import { app } from "../../../scripts/app.js";
// This file just needs to register the new widget type
function textUploadWidget(node, inputName, inputData, app) {
const widget = {
type: inputData[0], // "TEXTUPLOAD"
name: inputName,
size: [128, 88], // Widget size
draw(ctx, node, width, y) {}, // No need to draw anything
computeSize(...args) {
return [128, 88]; // Match the size
},
async serializeValue(nodeId, widgetIndex) {
return node.widgets[widgetIndex].value;
},
};
// Create the "Choose File" button
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "text/plain,.txt"; // <--- This is the important change
fileInput.style.display = "none";
// Handle file selection
fileInput.addEventListener("change", (event) => {
if (fileInput.files.length) {
uploadFile(fileInput.files[0]);
}
});
// Create the button that opens the file picker
const uploadButton = document.createElement("button");
uploadButton.type = "button";
uploadButton.innerText = "Choose .txt File to Upload";
uploadButton.className = "comfy-btn";
uploadButton.style.width = "100%"; // Make button fill widget
uploadButton.style.marginTop = "10px";
uploadButton.addEventListener("click", () => {
fileInput.click();
});
// Function to handle the upload
async function uploadFile(file) {
const body = new FormData();
// We use "image" to match the server's /upload/image endpoint
// The server doesn't care about the file type, just saves it.
body.append("image", file);
body.append("overwrite", "true");
widget.value = file.name; // Store the filename for the backend
uploadButton.innerText = "Uploading...";
try {
const response = await fetch("/upload/image", {
method: "POST",
body: body,
});
if (response.status === 200) {
uploadButton.innerText = file.name; // Show the new filename
node.setValue(file.name); // Set the node's internal value
} else {
alert(response.status + " - " + response.statusText);
uploadButton.innerText = "Choose .txt File to Upload";
}
} catch (error) {
alert(error);
uploadButton.innerText = "Choose .txt File to Upload";
}
}
// Add the button to the node's widget area
node.addDOMWidget(inputName, "button", uploadButton, widget);
document.body.appendChild(fileInput); // Add the hidden file input
// Handle drag and drop
node.onDragOver = function (e) {
if (e.dataTransfer.items.length > 0) {
const item = e.dataTransfer.items[0];
// Allow .txt files (which often have no MIME type) or text/plain
return item.kind === 'file' && (item.type === "text/plain" || item.type === "");
}
return false;
};
node.onDragDrop = function (e) {
let handled = false;
for (const file of e.dataTransfer.files) {
if (file.type === "text/plain" || file.name.endsWith(".txt")) {
uploadFile(file);
handled = true;
}
}
return handled;
};
return widget;
}
// Register our new "TEXTUPLOAD" widget with ComfyUI
app.registerWidget("TEXTUPLOAD", textUploadWidget);
+18 -23
View File
@@ -1,66 +1,61 @@
import os
import folder_paths
# --- Get Text Files ---
# 1. Get the ComfyUI 'input' directory
input_dir = folder_paths.get_input_directory()
# 2. Find all .txt files in that directory
# We os.path.isfile to make sure we don't grab directories
text_files = [
f for f in os.listdir(input_dir)
if os.path.isfile(os.path.join(input_dir, f)) and f.endswith(".txt")
]
# --- The Node Class ---
class LoadTextFile:
"""
A node that loads text from a file in the ComfyUI/input/ directory.
A node that loads text from a file.
It uses a custom widget to upload a .txt file.
"""
@classmethod
def INPUT_TYPES(s):
return {
"required": {
# This creates the dropdown widget with our file list
"file_name": (text_files, )
# This string "image" MUST match the name in the
# FormData.append("image", file) in the JS.
# It tells ComfyUI to use our new "TEXTUPLOAD" widget.
"image": ("TEXTUPLOAD", )
}
}
# What the node will output
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",) # Optional, but good practice
RETURN_NAMES = ("text",)
# The function that runs when the node is executed
FUNCTION = "load_text"
# The category in the right-click menu
CATEGORY = "Rathius_ComfyNodes/Utils"
# We don't want this node to run on file load, only when queued
def IS_CHANGED(self, **kwargs):
return float("inf")
def load_text(self, file_name):
# Get the full path to the file
file_path = os.path.join(input_dir, file_name)
def load_text(self, image):
# 'image' is the filename (e.g., "my_prompt.txt")
# The widget has already uploaded it to the 'input' folder.
file_path = os.path.join(folder_paths.get_input_directory(), image)
try:
# Open and read the file
with open(file_path, 'r', encoding='utf-8') as f:
text_content = f.read()
# Nodes must return their outputs as a tuple
# Return the text content as a tuple
return (text_content, )
except Exception as e:
print(f"[LoadTextFile] Error: {e}")
# Return the error as a string so you can see it in ComfyUI
return (f"Error loading file: {e}", )
# --- Node Registration ---
# This tells ComfyUI about our new node
NODE_CLASS_MAPPINGS = {
"LoadTextFile_Rathius": LoadTextFile
}
# This sets the name that appears in the Add Node menu
# I updated the display name to reflect its new function
NODE_DISPLAY_NAME_MAPPINGS = {
"LoadTextFile_Rathius": "Load Text from File"
"LoadTextFile_Rathius": "Load Text from File (Upload)"
}