mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-06 22:10:14 -03:00
feat(SaveImageLM): add add_loras_to_prompt toggle to restore legacy lora syntax line in metadata
This commit is contained in:
@@ -252,6 +252,13 @@ class SaveImageLM:
|
|||||||
"tooltip": "When enabled, embeds generation parameters into the saved image metadata. Disable to skip writing generation metadata.",
|
"tooltip": "When enabled, embeds generation parameters into the saved image metadata. Disable to skip writing generation metadata.",
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
"add_loras_to_prompt": (
|
||||||
|
"BOOLEAN",
|
||||||
|
{
|
||||||
|
"default": False,
|
||||||
|
"tooltip": "When enabled, appends the LoRA syntax line (e.g. <lora:name:strength>) after the positive prompt in the saved metadata.",
|
||||||
|
},
|
||||||
|
),
|
||||||
"add_counter_to_filename": (
|
"add_counter_to_filename": (
|
||||||
"BOOLEAN",
|
"BOOLEAN",
|
||||||
{
|
{
|
||||||
@@ -348,7 +355,7 @@ class SaveImageLM:
|
|||||||
type_lower = model_type.lower() if model_type else "other"
|
type_lower = model_type.lower() if model_type else "other"
|
||||||
return f"urn:air:{slug}:{type_lower}:civitai:{model_id}@{version_id}"
|
return f"urn:air:{slug}:{type_lower}:civitai:{model_id}@{version_id}"
|
||||||
|
|
||||||
def format_metadata(self, metadata_dict: dict) -> str:
|
def format_metadata(self, metadata_dict: dict, add_loras_to_prompt: bool = False) -> str:
|
||||||
"""Format metadata as A1111-compatible parameters string with Hashes JSON and Civitai resources."""
|
"""Format metadata as A1111-compatible parameters string with Hashes JSON and Civitai resources."""
|
||||||
if not metadata_dict: return ""
|
if not metadata_dict: return ""
|
||||||
|
|
||||||
@@ -458,7 +465,10 @@ class SaveImageLM:
|
|||||||
scheduler_name = scheduler_mapping.get(scheduler, scheduler) if scheduler else None
|
scheduler_name = scheduler_mapping.get(scheduler, scheduler) if scheduler else None
|
||||||
|
|
||||||
# Build output lines
|
# Build output lines
|
||||||
lines = [prompt] if prompt else [""]
|
prompt_line = prompt if prompt else ""
|
||||||
|
if add_loras_to_prompt and loras_text:
|
||||||
|
prompt_line = f"{prompt_line}\n{loras_text}" if prompt_line else loras_text
|
||||||
|
lines = [prompt_line] if prompt_line else [""]
|
||||||
if negative_prompt:
|
if negative_prompt:
|
||||||
lines.append(f"Negative prompt: {negative_prompt}")
|
lines.append(f"Negative prompt: {negative_prompt}")
|
||||||
|
|
||||||
@@ -793,6 +803,7 @@ class SaveImageLM:
|
|||||||
save_with_metadata=True,
|
save_with_metadata=True,
|
||||||
add_counter_to_filename=True,
|
add_counter_to_filename=True,
|
||||||
save_as_recipe=False,
|
save_as_recipe=False,
|
||||||
|
add_loras_to_prompt=False,
|
||||||
):
|
):
|
||||||
"""Save images with metadata"""
|
"""Save images with metadata"""
|
||||||
results = []
|
results = []
|
||||||
@@ -801,7 +812,7 @@ class SaveImageLM:
|
|||||||
raw_metadata = get_metadata()
|
raw_metadata = get_metadata()
|
||||||
metadata_dict = MetadataProcessor.to_dict(raw_metadata, id)
|
metadata_dict = MetadataProcessor.to_dict(raw_metadata, id)
|
||||||
|
|
||||||
metadata = self.format_metadata(metadata_dict)
|
metadata = self.format_metadata(metadata_dict, add_loras_to_prompt)
|
||||||
|
|
||||||
# Process filename_prefix with pattern substitution
|
# Process filename_prefix with pattern substitution
|
||||||
filename_prefix = self.format_filename(filename_prefix, metadata_dict)
|
filename_prefix = self.format_filename(filename_prefix, metadata_dict)
|
||||||
@@ -943,6 +954,7 @@ class SaveImageLM:
|
|||||||
save_with_metadata=True,
|
save_with_metadata=True,
|
||||||
add_counter_to_filename=True,
|
add_counter_to_filename=True,
|
||||||
save_as_recipe=False,
|
save_as_recipe=False,
|
||||||
|
add_loras_to_prompt=False,
|
||||||
):
|
):
|
||||||
"""Process and save image with metadata"""
|
"""Process and save image with metadata"""
|
||||||
# Make sure the output directory exists
|
# Make sure the output directory exists
|
||||||
@@ -974,6 +986,7 @@ class SaveImageLM:
|
|||||||
save_with_metadata,
|
save_with_metadata,
|
||||||
add_counter_to_filename,
|
add_counter_to_filename,
|
||||||
save_as_recipe,
|
save_as_recipe,
|
||||||
|
add_loras_to_prompt,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -86,6 +86,41 @@ def test_save_image_skips_png_parameters_when_metadata_disabled_and_keeps_workfl
|
|||||||
assert img.info["workflow"] == json.dumps(workflow)
|
assert img.info["workflow"] == json.dumps(workflow)
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_image_does_not_append_loras_to_prompt_by_default(monkeypatch, tmp_path):
|
||||||
|
_configure_save_paths(monkeypatch, tmp_path)
|
||||||
|
_configure_metadata(
|
||||||
|
monkeypatch,
|
||||||
|
{"prompt": "prompt text", "seed": 123, "loras": "<lora:foo:0.7>"},
|
||||||
|
)
|
||||||
|
|
||||||
|
node = SaveImageLM()
|
||||||
|
node.save_images([_make_image()], "ComfyUI", "png", id="node-1")
|
||||||
|
|
||||||
|
image_path = tmp_path / "sample_00001_.png"
|
||||||
|
with Image.open(image_path) as img:
|
||||||
|
assert "<lora:" not in img.info["parameters"]
|
||||||
|
assert img.info["parameters"] == "prompt text\nSeed: 123, Version: ComfyUI"
|
||||||
|
|
||||||
|
|
||||||
|
def test_save_image_appends_loras_to_prompt_when_enabled(monkeypatch, tmp_path):
|
||||||
|
_configure_save_paths(monkeypatch, tmp_path)
|
||||||
|
_configure_metadata(
|
||||||
|
monkeypatch,
|
||||||
|
{"prompt": "prompt text", "seed": 123, "loras": "<lora:foo:0.7>"},
|
||||||
|
)
|
||||||
|
|
||||||
|
node = SaveImageLM()
|
||||||
|
node.save_images(
|
||||||
|
[_make_image()], "ComfyUI", "png", id="node-1", add_loras_to_prompt=True
|
||||||
|
)
|
||||||
|
|
||||||
|
image_path = tmp_path / "sample_00001_.png"
|
||||||
|
with Image.open(image_path) as img:
|
||||||
|
assert img.info["parameters"] == (
|
||||||
|
"prompt text\n<lora:foo:0.7>\nSeed: 123, Version: ComfyUI"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_save_image_skips_jpeg_metadata_when_disabled(monkeypatch, tmp_path):
|
def test_save_image_skips_jpeg_metadata_when_disabled(monkeypatch, tmp_path):
|
||||||
_configure_save_paths(monkeypatch, tmp_path)
|
_configure_save_paths(monkeypatch, tmp_path)
|
||||||
_configure_metadata(monkeypatch, {"prompt": "prompt text", "seed": 123})
|
_configure_metadata(monkeypatch, {"prompt": "prompt text", "seed": 123})
|
||||||
@@ -451,6 +486,14 @@ class TestParameterDefaultConsistency:
|
|||||||
assert SaveImageLM.save_images.__defaults__[5] == 0
|
assert SaveImageLM.save_images.__defaults__[5] == 0
|
||||||
assert SaveImageLM.process_image.__defaults__[7] == 0
|
assert SaveImageLM.process_image.__defaults__[7] == 0
|
||||||
|
|
||||||
|
def test_add_loras_to_prompt_defaults_are_consistent(self):
|
||||||
|
input_types = SaveImageLM.INPUT_TYPES()
|
||||||
|
optional = input_types["optional"]
|
||||||
|
|
||||||
|
assert optional["add_loras_to_prompt"][1]["default"] is False
|
||||||
|
assert SaveImageLM.save_images.__defaults__[-1] is False
|
||||||
|
assert SaveImageLM.process_image.__defaults__[-1] is False
|
||||||
|
|
||||||
|
|
||||||
def test_png_does_not_pass_webp_method_or_jpeg_subsampling(monkeypatch, tmp_path):
|
def test_png_does_not_pass_webp_method_or_jpeg_subsampling(monkeypatch, tmp_path):
|
||||||
_configure_save_paths(monkeypatch, tmp_path)
|
_configure_save_paths(monkeypatch, tmp_path)
|
||||||
|
|||||||
Reference in New Issue
Block a user