| author | Alan Dipert
<alan@dipert.org> 2025-12-04 04:57:14 UTC |
| committer | Alan Dipert
<alan@dipert.org> 2025-12-04 04:57:14 UTC |
| parent | 29b881d4f8aa78c8f1aa27e11ecddd89a5c9da1b |
| .gitignore | +1 | -0 |
| README.md | +7 | -0 |
| render_text.py | +49 | -2 |
diff --git a/.gitignore b/.gitignore index c1f4693..b1c4696 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ test_booklet*.txt answer_key*.txt my_answers*.txt answers*.txt +*.pdf # OS/editor noise .DS_Store diff --git a/README.md b/README.md index 24ac745..b1306dd 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,13 @@ make run # generates JSON, booklet, and key cat test_booklet.txt # view the booklet cat answer_key.txt # view the key ``` +- **Optional PDF output:** Requires `pandoc` plus a PDF engine (wkhtmltopdf or weasyprint recommended). Example: + ```bash + python3 render_text.py --in generated_test.json \ + --test-out test_booklet.txt --key-out answer_key.txt \ + --test-pdf test_booklet.pdf --key-pdf answer_key.pdf + ``` + If no PDF engine is available, the script will skip PDF generation and report the issue. ## Generate Different Hardness Levels - **Standard (balanced):** diff --git a/render_text.py b/render_text.py index c1851e5..087d685 100644 --- a/render_text.py +++ b/render_text.py @@ -4,6 +4,9 @@ from __future__ import annotations import argparse import json from typing import Dict, Any +import subprocess +import shutil +import tempfile def parse_args() -> argparse.Namespace: @@ -11,6 +14,8 @@ def parse_args() -> argparse.Namespace: parser.add_argument("--in", dest="in_path", required=True) parser.add_argument("--test-out", dest="test_out", default="test_booklet.txt") parser.add_argument("--key-out", dest="key_out", default="answer_key.txt") + parser.add_argument("--test-pdf", dest="test_pdf", default=None, help="Optional PDF path for the booklet.") + parser.add_argument("--key-pdf", dest="key_pdf", default=None, help="Optional PDF path for the answer key.") return parser.parse_args() @@ -75,14 +80,56 @@ def render_key(data: Dict[str, Any]) -> str: return "\n".join(lines) +def _write_pdf(text: str, pdf_path: str, title: str) -> None: + """Render plain text to PDF via pandoc if available.""" + pandoc = shutil.which("pandoc") + if not pandoc: + raise RuntimeError("pandoc not found; cannot render PDF.") + with tempfile.NamedTemporaryFile("w", delete=False, suffix=".txt") as tmp: + tmp.write(f"{title}\n\n{text}") + tmp_path = tmp.name + engines = [e for e in ["wkhtmltopdf", "weasyprint", "pdflatex"] if shutil.which(e)] + if not engines: + engines = [None] # let pandoc pick default (may fail) + last_error = None + try: + for eng in engines: + cmd = [pandoc, tmp_path, "-o", pdf_path] + if eng: + cmd.extend(["--pdf-engine", eng]) + try: + subprocess.run(cmd, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + last_error = None + break + except subprocess.CalledProcessError as e: + last_error = e + if last_error: + raise RuntimeError( + "pandoc could not produce PDF; install a pdf engine such as wkhtmltopdf/weasyprint/pdflatex." + ) from last_error + finally: + try: + import os + + os.remove(tmp_path) + except OSError: + pass + + def main() -> None: args = parse_args() with open(args.in_path, "r", encoding="utf-8") as f: data = json.load(f) + booklet_text = render_booklet(data) + key_text = render_key(data) with open(args.test_out, "w", encoding="utf-8") as f: - f.write(render_booklet(data)) + f.write(booklet_text) with open(args.key_out, "w", encoding="utf-8") as f: - f.write(render_key(data)) + f.write(key_text) + if args.test_pdf: + _write_pdf(booklet_text, args.test_pdf, "ALAN Booklet") + if args.key_pdf: + _write_pdf(key_text, args.key_pdf, "ALAN Answer Key") if __name__ == "__main__":