diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-05 16:18:46 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-05 16:18:46 +0200 |
| commit | 871084b1dbf0fdc6e0a93860747252155b5e51f1 (patch) | |
| tree | 3d06ad0a7823ee4d8b4ff8f683a0d2e5c7b15fe0 | |
| parent | e460c721ae21bb1218978f9b7f601e0f830c0428 (diff) | |
| download | fanfictioner-871084b1dbf0fdc6e0a93860747252155b5e51f1.tar.gz fanfictioner-871084b1dbf0fdc6e0a93860747252155b5e51f1.zip | |
Retry Qwen edits that run out of VRAM with a 5 GB budget
Qwen-Image 2.1 edits with two reference sheets need about 10 GB of VRAM,
more than the 12 GB Arc leaves beside the desktop: prefix caching fails,
the retry without it fails too, and so does disabling caching up front.
Only an explicit --max-vram budget fits, by streaming weights (about
12 minutes per candidate), so retry once with vulkan0=5 when sd-cli
reports it cannot make enough memory available.
sd-cli logs [ERROR for the prefix caching failure it recovers from, so a
run whose images were all saved no longer counts as failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rwxr-xr-x | fanfictioner | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/fanfictioner b/fanfictioner index 9917540..db801bc 100755 --- a/fanfictioner +++ b/fanfictioner @@ -436,7 +436,9 @@ def run_sd(args, log, preview=None): print() if viewer: viewer.terminate() - if proc.returncode or "[ERROR" in Path(log).read_text(errors="replace"): + out = Path(log).read_text(errors="replace") + # sd-cli also logs [ERROR for steps it recovers from (Qwen prefix caching): every image saved wins. + if proc.returncode or ("[ERROR" in out and not re.search(r"\b(\d+)/\1 images saved", out)): return f"sd-cli failed (exit {proc.returncode})" return None @@ -484,6 +486,11 @@ def generate(d, profile, prompt, size, refs=()): preview.unlink(missing_ok=True) args += ["--preview", "proj", "--preview-path", str(preview)] err = run_sd(args, log, preview) + if err and "cannot make enough memory" in log.read_text(errors="replace"): + # ponytail: fixed 5 GB budget, fits a Qwen edit beside the desktop but streams weights, + # ~12 min per candidate; closing VRAM-heavy apps avoids this path. + print("out of VRAM, retrying with a 5 GB budget (slow) ...", flush=True) + err = run_sd(args + ["--max-vram", "vulkan0=5"], log, preview) files = [d / f"{seed}_{i}.png" for i in (1, 2, 3)] if not err and not all(f.exists() for f in files): err = "sd-cli wrote no output" @@ -901,6 +908,8 @@ def selftest(): assert run_sd(["true"], t / "ok.log") is None assert (t / "ok.log").read_text().startswith("true") assert run_sd(["sh", "-c", "echo '[ERROR] boom'"], t / "e.log") == "sd-cli failed (exit 0)" + assert run_sd(["sh", "-c", "echo '[ERROR] boom'; echo '3/3 images saved'"], t / "r.log") is None + assert run_sd(["sh", "-c", "echo '[ERROR] boom'; echo '1/3 images saved'"], t / "p.log") assert run_sd(["false"], t / "f.log") == "sd-cli failed (exit 1)" assert run_sd(["/nonexistent-sd-cli"], t / "n.log").startswith("cannot run /nonexistent-sd-cli") global LOG |
