aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-05 09:54:26 +0200
committerDanilo M. <danix@danix.xyz>2026-10-05 09:54:26 +0200
commitd3a038d02ffe35470a6e74c713b343c4b25427d0 (patch)
tree36aa218320a0aebcefe0bd884344da7e937b57bc
parent636337e4b6ed8a4178bc388a1c47c06c839ba841 (diff)
downloadfanfictioner-d3a038d02ffe35470a6e74c713b343c4b25427d0.tar.gz
fanfictioner-d3a038d02ffe35470a6e74c713b343c4b25427d0.zip
Tie page picks to their prompts and guard bad inputs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--README.md6
-rwxr-xr-xfanfictioner17
2 files changed, 20 insertions, 3 deletions
diff --git a/README.md b/README.md
index 8f64898..73ee9cf 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,12 @@ Plan review keys: `c` confirm, `e` edit in `$EDITOR`, `g` ask Gemma to revise,
`q` quit. Image review keys: `1`-`3` pick, `r` regenerate, `p` edit prompt,
`s` skip edit (edit stage only), `q` quit.
+A page can override the base model with a `Model: krea2` line in plan.md. To
+redo a page, delete `NNN.png` from the library and its `cand/pNNN_*` folder.
+To redo a reference sheet, delete `refs/<Name>.png`; pages already done keep
+the old look. A prompt edited with `p` applies until you pick and is not
+written back to plan.json.
+
## License
Copyright (C) 2026 Danilo M. <danix@danix.xyz>
diff --git a/fanfictioner b/fanfictioner
index 6a9581f..db434be 100755
--- a/fanfictioner
+++ b/fanfictioner
@@ -16,6 +16,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
+import hashlib
import http.client
import json
import os
@@ -420,7 +421,7 @@ def unload_llm():
"""Free VRAM for sd-cli. Idempotent: an unloaded or unreachable server is fine."""
try:
llm("/models/unload", {"model": LLM_MODEL}, timeout=10)
- except OSError:
+ except (OSError, ValueError):
pass
@@ -539,7 +540,8 @@ def refs_stage(chars, wd):
def page_stage(p, wd, out, base):
"""Base scene, then chained head edits; each pick kept in cand/pNNN so a quit resumes mid-page."""
- d = wd / "cand" / f"p{p['n']:03d}"
+ key = json.dumps([p["base_prompt"], p["orientation"], p["model"], p["edits"]])
+ d = wd / "cand" / f"p{p['n']:03d}_{hashlib.sha1(key.encode()).hexdigest()[:8]}"
size = SIZES[p["orientation"]]
scene = d / "base.png"
if not scene.exists():
@@ -689,8 +691,17 @@ def main():
return selftest()
if not a.story:
ap.error("story file required")
+ if not a.story.is_file():
+ ap.error(f"{a.story}: not a file")
+ if a.story.suffix == "":
+ ap.error("story file needs an extension, e.g. story.md")
try:
- lib = load_conf()["LIBRARY"]
+ try:
+ lib = load_conf().get("LIBRARY")
+ except FileNotFoundError:
+ lib = None
+ if not lib:
+ sys.exit(f"set LIBRARY in {CONF}")
wd = a.story.with_suffix("")
pj = plan_stage(a.story, wd)
chars, pages = todo(pj, wd, lib)