add SLPFilenamePrefix

This commit is contained in:
hetima
2026-01-27 14:09:37 +09:00
parent 9080596ca7
commit 897bfc83d9
6 changed files with 113 additions and 3 deletions
+13 -1
View File
@@ -30,7 +30,19 @@
デフォルトのローダーとほぼ同じです。LoRAファイルの指定部分がコンボボックスではなくテキストになっているのでSingle Line Pickerを直接繋げることができます。
出力パラメータ`stem`を持っています。LoRAファイルの拡張子を除いたファイル名を出力します([audioscavenger/save-image-extended-comfyui](https://github.com/audioscavenger/save-image-extended-comfyui) はLoRAの名前を参照することができますが、SLP Lora Loaderの`lora_name`を参照しようとするとエラーが出たため名前を`lora_name_text`に変更しています。この`lora_name_text`を参照したとしてもエラーにはなりませんが、正常な値は取得できません。`stem`出力を加工するなりして対応してください)。
出力パラメータ`stem`を持っています。LoRAファイルの拡張子を除いたファイル名を出力します。次節のSLP Filename Prefixで利用できます。
### SLP Filename Prefix
「画像を保存」などのファイルを書き出すノードは`filename_prefix(ファイル名_プレフィックス)`パラメータを持ち`%date:%`方式で現在の日付時刻を設定できます。ただしこれはフロントエンドで前処理されるため、実行中の出力と組み合わせることが難しいのです。`filename_prefix`にインプット接続しても日付時刻の処理はされません。
それを解決するためにこのノードでは、日付時刻の処理に加えてプレースホルダによる文字列置き換えを行った結果を出力します。「画像を保存」などの`filename_prefix`に有効な値を渡すことができます。
プレースホルダは`$1` `$2` `$3` `$4`と最大4個作ることができ、それぞれ同名のインプットで置き換えられます。入力は文字列と数値に対応しています。
![screecshot03](./assets/slp03.jpg)
## Changelog
+13 -1
View File
@@ -29,7 +29,19 @@ When select this node, a button marked with the ![icon](./assets/lora.svg) icon
It's almost identical to the default loader. Since the LoRA file selection part is text instead of a combo box so that connect a Single Line Picker directly.
It has an output parameter called `stem`. It outputs LoRA filename without file extension ([audioscavenger/save-image-extended-comfyui](https://github.com/audioscavenger/save-image-extended-comfyui) can reference LoRA name, but since attempting to reference `lora_name` in the SLP Lora Loader caused an error, the name has been changed to `lora_name_text`. Referencing this `lora_name_text` will not cause an error, but it will not retrieve the correct value. Please handle this by modifying the `stem` output or similar means).
It has an output parameter called `stem`. It outputs LoRA filename without file extension. Available in the next section's SLP Filename Prefix.
### SLP Filename Prefix
Nodes that export files, such as "Save Image" feature a `filename_prefix` parameter that can be set to the current date and time using the `%date:%` format. However, since this is preprocessed by the frontend, it is difficult to combine with backend's runtime output. Connecting an input to `filename_prefix` will not process the date and time.
To resolve this, this node outputs the result of processing the date and time, along with replacing placeholders with strings. You can pass valid value for `filename_prefix` such as "Save Image".
Placeholders can be created up to four: `$1`, `$2`, `$3`, and `$4`. Each is replaced with an input of the same name. Inputs support string and numeric values.
![screecshot03](./assets/slp03.jpg)
## Changelog
+3 -1
View File
@@ -1,17 +1,19 @@
from .single_line_picker import SLPSingleLinePicker
from .slp_lora_loader import SLPLoraLoader, SLPLoraLoaderModelOnly
from .slp_filename_prefix import SLPFilenamePrefix
NODE_CLASS_MAPPINGS = {
SLPSingleLinePicker.NAME: SLPSingleLinePicker,
SLPLoraLoader.NAME: SLPLoraLoader,
SLPLoraLoaderModelOnly.NAME: SLPLoraLoaderModelOnly,
SLPFilenamePrefix.NAME: SLPFilenamePrefix,
}
NODE_DISPLAY_NAME_MAPPINGS = {
SLPSingleLinePicker.NAME: SLPSingleLinePicker.DISPLAY_NAME,
SLPLoraLoader.NAME: SLPLoraLoader.DISPLAY_NAME,
SLPLoraLoaderModelOnly.NAME: SLPLoraLoaderModelOnly.DISPLAY_NAME,
SLPFilenamePrefix.NAME: SLPFilenamePrefix.DISPLAY_NAME,
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

+22
View File
@@ -0,0 +1,22 @@
const { app } = window.comfyAPI.app;
const { applyTextReplacements } = window.comfyAPI.utils;
app.registerExtension({
name: "hetima.SLPFilenamePrefix",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "HetimaSLPFilenamePrefix") {
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const ret = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
const widget = this.widgets.find((w) => w.name === "filename_prefix");
widget.serializeValue = () => {
return applyTextReplacements(app, widget.value);
};
return ret;
};
}
},
});
+62
View File
@@ -0,0 +1,62 @@
import re
class AnyType(str):
"""A special class that is always equal in not equal comparisons. Credit to pythongosssss"""
def __ne__(self, __value: object) -> bool:
return False
any_type = AnyType("*")
class SLPFilenamePrefix:
NAME = "HetimaSLPFilenamePrefix"
DISPLAY_NAME = "SLP Filename Prefix"
CATEGORY = "SingleLinePicker"
DESCRIPTION = "Builds a filename_prefix and return one includes placeholder replacements."
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"filename_prefix": ("STRING", {"multiline": False, "default": "%date:yyyy-MM-dd%/$1", "tooltip": 'can include "%date:%", "$1", "$2", "$3" and "$4"'}),
},
"optional": {
"$1": (any_type, {"multiline": False, "default": "", "forceInput": True, "tooltip": 'replace "$1" with this value'}),
"$2": (any_type, {"multiline": False, "default": "", "forceInput": True, "tooltip": 'replace "$2" with this value'}),
"$3": (any_type, {"multiline": False, "default": "", "forceInput": True, "tooltip": 'replace "$3" with this value'}),
"$4": (any_type, {"multiline": False, "default": "", "forceInput": True, "tooltip": 'replace "$4" with this value'}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("STRING",)
OUTPUT_TOOLTIPS = ("built filename_prefix",)
OUTPUT_NODE = True
FUNCTION = "execute"
def to_storing(self, val):
if isinstance(val, str) and len(val) > 0:
val = val.splitlines()[0]
trans = val.maketrans("?/<>\\:*|\"", "_________")
val = val.translate(trans)
return val
if isinstance(val, (int, float, bool)):
return str(val)
return ""
def execute(self, **kwargs):
filename_prefix = kwargs["filename_prefix"]
if not filename_prefix:
return ""
s1 = self.to_storing(kwargs.get("$1", ""))
s2 = self.to_storing(kwargs.get("$2", ""))
s3 = self.to_storing(kwargs.get("$3", ""))
s4 = self.to_storing(kwargs.get("$4", ""))
mapping = {"$1": s1, "$2": s2, "$3": s3, "$4": s4,}
pattern = re.compile("|".join(re.escape(k) for k in mapping.keys()))
filename_prefix = pattern.sub(lambda m: mapping[m.group(0)], filename_prefix)
return (filename_prefix,)