Commit ·
fc39079
1
Parent(s): f1d47d0
Restore image saving from tensor, dedupe duplicates, simplify result handling
Browse files
core/pipelines/sd_image_pipeline.py
CHANGED
|
@@ -3,6 +3,7 @@ import random
|
|
| 3 |
import shutil
|
| 4 |
import torch
|
| 5 |
import gradio as gr
|
|
|
|
| 6 |
from typing import List, Dict, Any
|
| 7 |
|
| 8 |
|
|
@@ -33,32 +34,53 @@ class SdImagePipeline(BasePipeline):
|
|
| 33 |
"""
|
| 34 |
progress(0.4, desc="Executing workflow...")
|
| 35 |
initial_objects = {}
|
| 36 |
-
# Execute the workflow; the SaveImage node returns
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
#
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
import hashlib
|
| 50 |
unique_hashes = set()
|
| 51 |
deduped_paths = []
|
| 52 |
-
for p in
|
|
|
|
| 53 |
try:
|
| 54 |
-
with open(
|
| 55 |
h = hashlib.sha256(f.read()).hexdigest()
|
| 56 |
if h not in unique_hashes:
|
| 57 |
unique_hashes.add(h)
|
| 58 |
-
deduped_paths.append(
|
| 59 |
-
except Exception
|
| 60 |
-
|
| 61 |
-
deduped_paths.append(p)
|
| 62 |
return deduped_paths
|
| 63 |
|
| 64 |
def run(self, ui_inputs: Dict, progress):
|
|
@@ -218,20 +240,8 @@ class SdImagePipeline(BasePipeline):
|
|
| 218 |
progress=progress
|
| 219 |
)
|
| 220 |
|
| 221 |
-
# The workflow
|
| 222 |
-
|
| 223 |
-
# metadata injection is required.
|
| 224 |
-
# Clean up any temporary files that were created for the workflow inputs.
|
| 225 |
-
# The ``finally`` block below already handles this cleanup.
|
| 226 |
-
# Simply return the list of file paths obtained from the workflow.
|
| 227 |
-
# (If ``results`` is a single string, convert it to a list for Gradio.)
|
| 228 |
-
if isinstance(results, (list, tuple)):
|
| 229 |
-
final_results = list(results)
|
| 230 |
-
else:
|
| 231 |
-
final_results = [results]
|
| 232 |
-
|
| 233 |
-
# The surrounding ``try``/``finally`` handles temp file cleanup.
|
| 234 |
-
return final_results
|
| 235 |
finally:
|
| 236 |
for temp_file in temp_files_to_clean:
|
| 237 |
if temp_file and os.path.exists(temp_file):
|
|
|
|
| 3 |
import shutil
|
| 4 |
import torch
|
| 5 |
import gradio as gr
|
| 6 |
+
from PIL import Image
|
| 7 |
from typing import List, Dict, Any
|
| 8 |
|
| 9 |
|
|
|
|
| 34 |
"""
|
| 35 |
progress(0.4, desc="Executing workflow...")
|
| 36 |
initial_objects = {}
|
| 37 |
+
# Execute the workflow; the SaveImage node returns the image tensor(s).
|
| 38 |
+
decoded_images_tensor = WorkflowExecutor.execute_workflow(workflow, initial_objects=initial_objects)
|
| 39 |
+
|
| 40 |
+
# Convert tensors to PIL images, attach metadata, and save them to the output folder.
|
| 41 |
+
out_dir = os.path.abspath(OUTPUT_DIR)
|
| 42 |
+
os.makedirs(out_dir, exist_ok=True)
|
| 43 |
+
saved_file_paths = []
|
| 44 |
+
start_seed = ui_inputs['seed'] if ui_inputs['seed'] != -1 else random.randint(0, 2**64 - 1)
|
| 45 |
+
for i in range(decoded_images_tensor.shape[0]):
|
| 46 |
+
img_tensor = decoded_images_tensor[i]
|
| 47 |
+
pil_image = Image.fromarray((img_tensor.cpu().numpy() * 255.0).astype("uint8"))
|
| 48 |
+
current_seed = start_seed + i
|
| 49 |
+
|
| 50 |
+
width_for_meta = ui_inputs.get('width', 'N/A')
|
| 51 |
+
height_for_meta = ui_inputs.get('height', 'N/A')
|
| 52 |
+
|
| 53 |
+
params_string = f"{ui_inputs['positive_prompt']}\nNegative prompt: {ui_inputs['negative_prompt']}\n"
|
| 54 |
+
params_string += f"Steps: {ui_inputs['num_inference_steps']}, Sampler: {ui_inputs['sampler']}, Scheduler: {ui_inputs['scheduler']}, CFG scale: {ui_inputs['guidance_scale']}, Seed: {current_seed}, Size: {width_for_meta}x{height_for_meta}, Base Model: {ui_inputs['model_display_name']}"
|
| 55 |
+
if ui_inputs['task_type'] != 'txt2img':
|
| 56 |
+
params_string += f", Denoise: {ui_inputs['denoise']}"
|
| 57 |
+
if ui_inputs.get('clip_skip') and ui_inputs['clip_skip'] != 1:
|
| 58 |
+
params_string += f", Clip skip: {abs(ui_inputs['clip_skip'])}"
|
| 59 |
+
if loras_string:
|
| 60 |
+
params_string += f", {loras_string}"
|
| 61 |
+
|
| 62 |
+
pil_image.info = {'parameters': params_string.strip()}
|
| 63 |
+
filename = f"gen_{random.randint(1000000, 9999999)}.png"
|
| 64 |
+
filepath = os.path.join(out_dir, filename)
|
| 65 |
+
pil_image.save(filepath, "PNG")
|
| 66 |
+
saved_file_paths.append(filepath)
|
| 67 |
+
|
| 68 |
+
# After both the internal SaveImage node (which already wrote files) and the above
|
| 69 |
+
# manual save, the output directory may contain duplicate images. Deduplicate by
|
| 70 |
+
# content hash (SHA‑256) and return a list of unique file paths.
|
| 71 |
import hashlib
|
| 72 |
unique_hashes = set()
|
| 73 |
deduped_paths = []
|
| 74 |
+
for p in sorted(os.listdir(out_dir)):
|
| 75 |
+
full_path = os.path.join(out_dir, p)
|
| 76 |
try:
|
| 77 |
+
with open(full_path, "rb") as f:
|
| 78 |
h = hashlib.sha256(f.read()).hexdigest()
|
| 79 |
if h not in unique_hashes:
|
| 80 |
unique_hashes.add(h)
|
| 81 |
+
deduped_paths.append(full_path)
|
| 82 |
+
except Exception:
|
| 83 |
+
continue
|
|
|
|
| 84 |
return deduped_paths
|
| 85 |
|
| 86 |
def run(self, ui_inputs: Dict, progress):
|
|
|
|
| 240 |
progress=progress
|
| 241 |
)
|
| 242 |
|
| 243 |
+
# The workflow already saved images and returned a deduplicated list of file paths.
|
| 244 |
+
return results
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 245 |
finally:
|
| 246 |
for temp_file in temp_files_to_clean:
|
| 247 |
if temp_file and os.path.exists(temp_file):
|