Files
artyclaw-artyclaw-comfy/py/debugtextsaver.py
T
2026-04-05 20:32:56 +02:00

115 lines
4.3 KiB
Python

# ======================================================================
# Node Pack: artyclaw-comfy
# Author: artyclaw
# Version: 1.0.0
# Description: A power-user toolkit for prompt logic, IO, and RNG.
# ======================================================================
# __init__.py
# DebugTextSaver — write or append text with real newlines and a timestamp header
# Now with extra debug prints.
import os
import re
from datetime import datetime
import traceback
NODE_NAME = "DebugTextSaver"
class DebugTextSaver:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"string": ("STRING", {"multiline": True, "default": ""}),
"output_file_path": ("STRING", {"default": "output/debug"}),
"file_name": ("STRING", {"default": "debug_log"}),
},
"optional": {
"file_extension": ("STRING", {"default": "txt"}),
"append": ("BOOLEAN", {"default": False}),
}
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("file_path",)
FUNCTION = "save"
CATEGORY = "text/utils"
def save(self, string, output_file_path="output/debug", file_name="debug_log",
file_extension="txt", append=False):
print("[DebugTextSaver] --- run start ---")
# Expand escape sequences: \n, \\n, \r\n → actual newlines
print(f"[DebugTextSaver] raw input string: {repr(string)}")
# Ensure we have a str
if not isinstance(string, str):
string = str(string)
def normalize_escapes(s: str) -> str:
"""
Convert only a small set of literal escape sequences to real characters:
- \\r\\n -> newline
- \\n -> newline
- \\r -> newline
- \\t -> tab
Collapse double backslashes into a single backslash so that sequences like
'\\\\N' become '\\N' (a literal backslash + 'N') and
will not be interpreted by any codec.
"""
# Convert common literal escapes to real characters
s = s.replace('\\r\\n', '\n').replace('\\n', '\n').replace('\\r', '\n').replace('\\t', '\t')
# Collapse double backslashes -> single backslash
s = s.replace('\\\\', '\\')
return s
clean_text = normalize_escapes(string)
# Normalize any remaining CR/LF to single \n
clean_text = re.sub(r'\r\n?', '\n', clean_text)
# Timestamp header
timestamp = datetime.now().strftime("[%Y-%m-%d %H:%M:%S]")
clean_text = f"{timestamp}\n{clean_text.strip()}\n"
# Build directory and filename
if not output_file_path:
output_file_path = "output/debug"
print("[DebugTextSaver] output_file_path was empty, using fallback 'output/debug'")
base_dir = os.path.abspath(output_file_path)
print(f"[DebugTextSaver] target directory (abs): {base_dir}")
os.makedirs(base_dir, exist_ok=True)
safe_name = re.sub(r"[^\w\-.]", "_", file_name.strip())
if not safe_name:
safe_name = datetime.now().strftime("debug_%Y%m%d_%H%M%S")
print(f"[DebugTextSaver] file_name was empty, generated: {safe_name}")
ext = file_extension.strip().lstrip(".") or "txt"
file_path = os.path.join(base_dir, f"{safe_name}.{ext}")
print(f"[DebugTextSaver] final file path: {file_path}")
# Choose mode
mode = "a" if append else "w"
print(f"[DebugTextSaver] open mode: {mode}")
# Write (append or overwrite)
try:
with open(file_path, mode, encoding="utf-8", newline="\n") as f:
f.write(clean_text)
print(f"[DebugTextSaver] wrote {len(clean_text)} bytes")
except Exception as e:
print("[DebugTextSaver] ERROR while writing file!")
traceback.print_exc()
# return empty path on error so you see it downstream
return ("",)
print("[DebugTextSaver] --- run end ---")
return (file_path,)
NODE_CLASS_MAPPINGS = {"DebugTextSaver": DebugTextSaver}
NODE_DISPLAY_NAME_MAPPINGS = {"DebugTextSaver": "Debug Text Saver"}