aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-05 16:18:46 +0200
committerDanilo M. <danix@danix.xyz>2026-10-05 16:18:46 +0200
commit871084b1dbf0fdc6e0a93860747252155b5e51f1 (patch)
tree3d06ad0a7823ee4d8b4ff8f683a0d2e5c7b15fe0
parente460c721ae21bb1218978f9b7f601e0f830c0428 (diff)
downloadfanfictioner-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-xfanfictioner11
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