smart_image_gen v0.7.8: per-job filename_prefix + source-image diagnostic

User reported observing a wrong image returned. Two hardenings:

1. _job_prefix() generates a per-submission filename_prefix
   ('smartedit_<10hex>', 'smartinpaint_<10hex>', 'smartgen_<10hex>')
   so SaveImage outputs from concurrent jobs sit in their own
   namespace and ComfyUI's auto-incrementing counter can never
   produce filenames that overlap across jobs. With a shared prefix,
   if a queued job's history-fetch ever raced past its own SaveImage
   record there was a theoretical (if unlikely) path to picking up
   another job's _00001_.png. Per-job prefix kills that vector.

2. edit_image now emits the source image's SHA-1 and byte count in a
   status event before uploading to ComfyUI. If a future 'wrong
   image' report comes in, that hash should match the prior
   generation's output — if it doesn't, we know
   _extract_attached_image picked up the wrong source rather than
   ComfyUI returning the wrong file. Hashlib import is local so the
   module's import surface stays clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 18:22:45 -05:00
co-authored by Claude Opus 4.7
parent d8c8421361
commit a1af88a632
@@ -1,7 +1,7 @@
"""
title: Smart Image Generator & Editor (ComfyUI)
author: ai-stack
version: 0.7.7
version: 0.7.8
description: Generate or edit images via ComfyUI with automatic SDXL
checkpoint routing. Two methods — generate_image (txt2img) and
edit_image (img2img on the user's most recently attached image). The
@@ -263,6 +263,12 @@ def _seed_value(seed: int) -> int:
return seed if seed > 0 else int(time.time() * 1000) % (2**31)
def _job_prefix(kind: str) -> str:
"""Per-submission filename_prefix so SaveImage outputs from concurrent
jobs can never share an auto-numbered counter and cross over."""
return f"{kind}_{uuid.uuid4().hex[:10]}"
def _build_txt2img(positive: str, negative: str, settings: dict,
width: int, height: int, seed: int) -> dict:
"""
@@ -286,7 +292,7 @@ def _build_txt2img(positive: str, negative: str, settings: dict,
"7": {"class_type": "CLIPTextEncode", "inputs": {"text": negative, "clip": ["10", 0]}},
"8": {"class_type": "VAEDecode", "inputs": {"samples": ["3", 0], "vae": ["4", 2]}},
"9": {"class_type": "SaveImage",
"inputs": {"filename_prefix": "smartgen", "images": ["8", 0]}},
"inputs": {"filename_prefix": _job_prefix("smartgen"), "images": ["8", 0]}},
"10": {"class_type": "CLIPSetLastLayer",
"inputs": {"stop_at_clip_layer": -settings["clip_skip"],
"clip": ["4", 1]}},
@@ -329,7 +335,7 @@ def _build_inpaint(positive: str, negative: str, settings: dict,
"7": {"class_type": "CLIPTextEncode", "inputs": {"text": negative, "clip": ["10", 0]}},
"8": {"class_type": "VAEDecode", "inputs": {"samples": ["3", 0], "vae": ["4", 2]}},
"9": {"class_type": "SaveImage",
"inputs": {"filename_prefix": "smartinpaint", "images": ["8", 0]}},
"inputs": {"filename_prefix": _job_prefix("smartinpaint"), "images": ["8", 0]}},
"10": {"class_type": "CLIPSetLastLayer",
"inputs": {"stop_at_clip_layer": -settings["clip_skip"],
"clip": ["4", 1]}},
@@ -381,7 +387,7 @@ def _build_img2img(positive: str, negative: str, settings: dict,
"7": {"class_type": "CLIPTextEncode", "inputs": {"text": negative, "clip": ["10", 0]}},
"8": {"class_type": "VAEDecode", "inputs": {"samples": ["3", 0], "vae": ["4", 2]}},
"9": {"class_type": "SaveImage",
"inputs": {"filename_prefix": "smartedit", "images": ["8", 0]}},
"inputs": {"filename_prefix": _job_prefix("smartedit"), "images": ["8", 0]}},
"10": {"class_type": "CLIPSetLastLayer",
"inputs": {"stop_at_clip_layer": -settings["clip_skip"],
"clip": ["4", 1]}},
@@ -943,7 +949,14 @@ class Tools:
"(paperclip / drag-drop), or call generate_image instead."
)
await emit("Uploading source to ComfyUI…")
# Diagnostic emit so a misrouted source ("wrong image
# returned") shows up in the status track instead of being
# invisible. SHA-1 is fast and the first 8 hex chars are
# plenty to compare against the prior generation's hash if
# cross-talk is suspected.
import hashlib # local import — keeps the module import surface clean
src_hash = hashlib.sha1(raw_in).hexdigest()[:8]
await emit(f"Uploading source to ComfyUI… (sha1={src_hash}, {len(raw_in)} bytes)")
uploaded_name = await _upload_to_comfyui(session, base, raw_in)
if not uploaded_name:
return "Failed to upload source image to ComfyUI."