aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-05 09:35:52 +0200
committerDanilo M. <danix@danix.xyz>2026-10-05 09:35:52 +0200
commitef974d3a424723429ad7d080c3d343939e22119a (patch)
tree421a2916b4dc2c738e0d4958d41eecf2781e5172
parent33aaeb67006a46ac8da79dbc365e31bc1fa0746f (diff)
downloadfanfictioner-ef974d3a424723429ad7d080c3d343939e22119a.tar.gz
fanfictioner-ef974d3a424723429ad7d080c3d343939e22119a.zip
Add fanfictioner skeleton and README
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--README.md43
-rwxr-xr-xfanfictioner56
2 files changed, 99 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8f64898
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# fanfictioner
+
+Turn a story idea into a text-free illustrated book. A local Gemma model
+(llama-server) plans the pages and writes the image prompts; `sd-cli`
+(stable-diffusion.cpp) draws them. You pick among three candidates at every
+image stage. Pages land in the book-reader library as `NNN.png`.
+
+## Requirements
+
+- Python 3, stdlib only
+- llama-server in router mode on `localhost:8181` serving `Gemma4-12B-qat-mtp`
+- `sd-cli` with Vulkan, models under `/data/LLM-models/SD`
+- ImageMagick 7 (`magick`), kitty (`kitty +kitten icat`), `$EDITOR`
+- `~/.config/book-reader.conf` with a `LIBRARY="..."` line
+
+## Usage
+
+ fanfictioner story.md [--base zimage|krea2]
+ fanfictioner --selftest
+
+Work files go to a directory named after the story (`stories/rooftop.md` ->
+`stories/rooftop/`): `plan.md`, `plan.json`, `refs/`, `cand/`. Quit any time
+with `q` or Ctrl-C; the next run resumes from what is on disk.
+
+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.
+
+## License
+
+Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License version 2 as published by the Free
+Software Foundation. See `LICENSE`.
+
+## Development Approach
+
+This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.
+
+All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.
+
+The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.
diff --git a/fanfictioner b/fanfictioner
new file mode 100755
index 0000000..49ec9b7
--- /dev/null
+++ b/fanfictioner
@@ -0,0 +1,56 @@
+#!/usr/bin/env python3
+# fanfictioner: turn a story idea into a text-free illustrated book.
+# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import argparse
+import json
+import os
+import random
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import urllib.request
+from pathlib import Path
+
+LLM_URL = "http://localhost:8181"
+LLM_MODEL = "Gemma4-12B-qat-mtp"
+SD_DIR = Path("/data/LLM-models/SD")
+CONF = Path.home() / ".config/book-reader.conf"
+
+
+def selftest():
+ print("selftest ok")
+
+
+def main():
+ ap = argparse.ArgumentParser(description="Turn story.md into a text-free illustrated book.")
+ ap.add_argument("story", nargs="?", type=Path, help="story idea in free prose")
+ ap.add_argument("--base", choices=("zimage", "krea2"), default="zimage",
+ help="base model for pages without a Model: line")
+ ap.add_argument("--selftest", action="store_true", help="run built-in checks and exit")
+ a = ap.parse_args()
+ if a.selftest:
+ return selftest()
+ if not a.story:
+ ap.error("story file required")
+
+
+if __name__ == "__main__":
+ main()