Studio diffusion (Phase 6): img2img / inpaint / edit / LoRA / upscale on the native engine
Builds on Phase 4's native stable-diffusion.cpp engine, extending it from
text-to-image to the wider feature surface, since sd.cpp supports all of these
through the binary already. Pure command-builder additions plus one engine
method, so the txt2img path is unchanged.
- sd_cpp_args.py: SdCppGenParams gains image-conditioning fields. init_img +
strength make a run img2img, adding mask makes it inpaint, ref_images drives
FLUX-Kontext / Qwen-Image-Edit style editing (repeated --ref-image), and
lora_dir + the <lora:name:weight> prompt syntax select LoRAs. New
SdCppUpscaleParams + build_sd_cpp_upscale_command for the ESRGAN upscale run
mode (input image + esrgan model, no prompt / text encoders).
- sd_cpp_engine.py: the subprocess runner is factored into a shared _run() so
generate() (now carrying the conditioning flags) and a new upscale() reuse
the same streaming / error / output-check path.
- scripts/sd_cpp_smoke.py: --task {txt2img,img2img,upscale} with --init-img /
--strength / --upscale-model / --upscale-repeats.
Tests: 10 new across the img2img / inpaint / edit / LoRA flag construction, the
upscale builder and its validation, and the engine's img2img + upscale paths.
Full diffusion suite 176 passing.
Verified on a B200 box through SdCppEngine: img2img (Z-Image-Turbo Q4_K, the
init image conditioned at strength 0.6, 4.8s) and ESRGAN upscale
(512x512 -> 2048x2048 via RealESRGAN_x4plus_anime_6B, 2.7s), both producing
coherent images. Video and the diffusers-path feature wiring are deferred.
This commit is contained in:
parent
33977e0991
commit
703d2df687
5 changed files with 283 additions and 30 deletions
|
|
@ -41,6 +41,7 @@ from core.inference.diffusion_memory import ( # noqa: E402
|
|||
from core.inference.sd_cpp_args import ( # noqa: E402
|
||||
SdCppGenParams,
|
||||
SdCppModelFiles,
|
||||
SdCppUpscaleParams,
|
||||
offload_flags,
|
||||
)
|
||||
from core.inference.sd_cpp_engine import SdCppEngine, find_sd_cpp_binary # noqa: E402
|
||||
|
|
@ -55,9 +56,15 @@ _MODE_TO_POLICY = {
|
|||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
p = argparse.ArgumentParser(description = "Native sd-cli engine smoke test.")
|
||||
p.add_argument("--task", default = "txt2img", choices = ["txt2img", "img2img", "upscale"])
|
||||
p.add_argument("--binary", default = None, help = "sd-cli path (else env / finder)")
|
||||
p.add_argument("--family", default = "z-image")
|
||||
p.add_argument("--diffusion-model", required = True)
|
||||
p.add_argument("--diffusion-model", default = None)
|
||||
# img2img + upscale inputs
|
||||
p.add_argument("--init-img", default = None)
|
||||
p.add_argument("--strength", type = float, default = 0.6)
|
||||
p.add_argument("--upscale-model", default = None)
|
||||
p.add_argument("--upscale-repeats", type = int, default = 1)
|
||||
p.add_argument("--vae", default = None)
|
||||
p.add_argument("--clip_l", default = None)
|
||||
p.add_argument("--t5xxl", default = None)
|
||||
|
|
@ -90,6 +97,28 @@ def main(argv: list[str] | None = None) -> int:
|
|||
)
|
||||
return 2
|
||||
|
||||
out = Path(args.out_image)
|
||||
|
||||
if args.task == "upscale":
|
||||
if not args.init_img or not args.upscale_model:
|
||||
print("ERROR: upscale needs --init-img and --upscale-model.", flush = True)
|
||||
return 2
|
||||
t0 = time.time()
|
||||
result = engine.upscale(
|
||||
SdCppUpscaleParams(input_image = args.init_img, upscale_model = args.upscale_model,
|
||||
repeats = args.upscale_repeats),
|
||||
output_path = str(out), verbose = True, timeout = args.timeout,
|
||||
on_log = lambda ln: print(f" [sd] {ln}", flush = True),
|
||||
)
|
||||
dt = time.time() - t0
|
||||
print(f"\nOK: upscaled {result} ({result.stat().st_size/1024:.0f} KB) in {dt:.1f}s", flush = True)
|
||||
print("SD-CPP-SMOKE-OK", flush = True)
|
||||
return 0
|
||||
|
||||
if not args.diffusion_model:
|
||||
print("ERROR: --diffusion-model is required for txt2img / img2img.", flush = True)
|
||||
return 2
|
||||
|
||||
files = SdCppModelFiles(
|
||||
diffusion_model = args.diffusion_model,
|
||||
vae = args.vae,
|
||||
|
|
@ -98,20 +127,22 @@ def main(argv: list[str] | None = None) -> int:
|
|||
llm = args.llm,
|
||||
qwen2vl = args.qwen2vl,
|
||||
)
|
||||
is_img2img = args.task == "img2img"
|
||||
params = SdCppGenParams(
|
||||
prompt = args.prompt,
|
||||
negative_prompt = args.negative_prompt,
|
||||
width = args.width,
|
||||
height = args.height,
|
||||
steps = args.steps,
|
||||
cfg_scale = args.cfg_scale,
|
||||
seed = args.seed,
|
||||
prompt = args.prompt, negative_prompt = args.negative_prompt,
|
||||
width = args.width, height = args.height, steps = args.steps,
|
||||
cfg_scale = args.cfg_scale, seed = args.seed,
|
||||
init_img = args.init_img if is_img2img else None,
|
||||
strength = args.strength if is_img2img else None,
|
||||
)
|
||||
if is_img2img and not args.init_img:
|
||||
print("ERROR: img2img needs --init-img.", flush = True)
|
||||
return 2
|
||||
policy = _MODE_TO_POLICY[args.memory_mode]
|
||||
off = offload_flags(policy)
|
||||
print(f"task: {args.task}" + (f" (init={args.init_img}, strength={args.strength})" if is_img2img else ""), flush = True)
|
||||
print(f"memory: {args.memory_mode} -> policy={policy} -> flags={off}", flush = True)
|
||||
|
||||
out = Path(args.out_image)
|
||||
t0 = time.time()
|
||||
result = engine.generate(
|
||||
files,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue