diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-05 13:35:51 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-05 13:35:51 +0200 |
| commit | 3c07c0e394ec60408e7856f1e51855a11043e3e6 (patch) | |
| tree | 04c70b8c0dd8783b14fc788fe28a0a0d2c0787dd | |
| parent | 50ccd6bad7e791179a7000811fcff139619238fb (diff) | |
| download | fanfictioner-3c07c0e394ec60408e7856f1e51855a11043e3e6.tar.gz fanfictioner-3c07c0e394ec60408e7856f1e51855a11043e3e6.zip | |
Report progress and choices while reviewing candidates
sd-cli ran silently for minutes. Show a self-overwriting status line with
the elapsed time and sd-cli's latest progress output, and print a line for
every pick, regenerate, prompt edit, skip and reused earlier pick.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rwxr-xr-x | fanfictioner | 21 |
1 files changed, 21 insertions, 0 deletions
diff --git a/fanfictioner b/fanfictioner index 7d53bce..132e46a 100755 --- a/fanfictioner +++ b/fanfictioner @@ -349,6 +349,15 @@ def mem_available_kb(meminfo): return int(re.search(r"MemAvailable:\s+(\d+)", meminfo)[1]) +def progress(start, log): + """One self-overwriting status line: elapsed time and sd-cli's latest progress output.""" + with open(log, "rb") as f: + f.seek(max(0, os.path.getsize(log) - 4096)) + last = next((x for x in reversed(re.split(r"[\r\n]", f.read().decode(errors="replace"))) if x.strip()), "") + width = shutil.get_terminal_size().columns - 1 + print(f"\r{int(time.time() - start):4d}s {last.strip()}"[:width].ljust(width), end="", flush=True) + + def run_sd(args, log): """Run sd-cli with output in log; return an error string or None.""" with open(log, "w") as f: @@ -358,9 +367,11 @@ def run_sd(args, log): proc = subprocess.Popen(args, stdout=f, stderr=subprocess.STDOUT) except OSError as e: return f"cannot run {args[0]}: {e}" + start = time.time() try: while proc.poll() is None: time.sleep(2) + progress(start, log) if proc.poll() is None and \ mem_available_kb(Path("/proc/meminfo").read_text()) < MIN_RAM_KB: proc.kill() @@ -370,6 +381,8 @@ def run_sd(args, log): proc.kill() proc.wait() raise + finally: + print() if proc.returncode or "[ERROR" in Path(log).read_text(errors="replace"): return f"sd-cli failed (exit {proc.returncode})" return None @@ -452,18 +465,22 @@ def review(d, profile, prompt, size, refs=(), skip=False): k = "q" if k in ("1", "2", "3") and not err: log(f"{stage} pick {k}, seed {seed + int(k) - 1}, {files[int(k) - 1].name}") + print(f"picked {k} (seed {seed + int(k) - 1})") return files[int(k) - 1] if k == "r": log(f"{stage} regenerate") + print("regenerating with a new seed") break if k == "p": (d / "prompt.txt").write_text(prompt) editor(d / "prompt.txt") prompt = (d / "prompt.txt").read_text().strip() or prompt log(f"{stage} prompt edited: {prompt}") + print(f"regenerating with prompt:\n{prompt}") break if k == "s" and skip: log(f"{stage} skip edit") + print("edit skipped, scene kept as is") return None if k == "q": log(f"{stage} quit") @@ -595,6 +612,8 @@ def page_stage(p, wd, out, base): if not scene.exists(): print(f"\n== page {p['n']}: base scene") keep(review(d / "base", p["model"] or base, p["base_prompt"], size), scene) + else: + print(f"page {p['n']}: base scene reused from earlier pick") for i, e in enumerate(p["edits"], 1): nxt = d / f"edit{i}.png" if not nxt.exists(): @@ -604,6 +623,8 @@ def page_stage(p, wd, out, base): for n in e["characters"]] pick = review(d / f"edit{i}", "qwen_edit", e["prompt"], size, refs, skip=True) keep(pick or scene, nxt) + else: + print(f"page {p['n']}: edit {i} ({', '.join(e['characters'])}) reused from earlier pick") scene = nxt keep(scene, out) log(f"page {p['n']} -> {out}") |
