KDP PDF β€” Upload a Design, Get a PDF

Drop a cover image β†’ the app uses AI to design a journal interior, stamps your cover on top, upscales to 300 DPI, and gives you a print-ready KDP PDF. One image-generation call per book.

Pipeline

Cover + theme note
   β”‚
   β–Ό
OpenRouter /v1/images (google/gemini-3.1-flash-lite-image)
   β”‚
   β–Ό
Pillow β€” stamp cover on top 1.5 in
   β”‚
   β–Ό
Pillow β€” LANCZOS upscale to 300 DPI + sharpen
   β”‚
   β–Ό
ReportLab β€” embed as N pages of a 6Γ—9 in PDF
   β”‚
   β–Ό
outputs/{filename}.pdf

Quickstart

  1. Install dependencies

    pip install -r requirements.txt
    
  2. Add the API key

    Create .streamlit/secrets.toml (gitignored):

    OPENROUTER_API_KEY = "sk-or-v1-YOUR-FRESH-KEY"
    
  3. Run

    streamlit run app.py
    
  4. Use

    • Upload a cover image (PNG / JPG / WebP).
    • (Optional) Add a short theme note, e.g. "golden retriever playing pickleball on a court".
    • Click Generate PDF and download the result.

Cost

One image-generation call per book via OpenRouter. The user pays OpenRouter directly. The exact price depends on the model; see the OpenRouter models page.

If your API key was ever shared in chat, email, or a screenshot, rotate it in the OpenRouter dashboard before using.

Files

File What it does
app.py Streamlit UI: upload, settings, generate, download
engine.py Pipeline: OpenRouter call, stamp, upscale, PDF
OPENROUTER_PROMPT.txt The one-shot prompt sent to the AI. Edit this to tune the design.
requirements.txt reportlab, streamlit, Pillow, svglib, requests
assets/ Sample cover images (reference only)
outputs/ Generated PDFs (gitignored)
PROMPT.txt V7 LLM-blueprint prompt (legacy, reference only)
FLOW_PROMPT.txt Google Flow visual-mockup prompt (reference only)

CLI usage

python engine.py --cover assets/golden_retriever_pickleball.png \
                 --out  my_book \
                 --theme "golden retriever playing pickleball" \
                 --pages 1

Outputs outputs/my_book.pdf.

Deploy to Hugging Face Spaces

  1. Push the repo to a new Space (Streamlit).
  2. In the Space's Settings β†’ Variables and secrets, add:
    • OPENROUTER_API_KEY (Secret)
  3. Space boots clean. Free tier supports Pillow + requests + reportlab (no torch / realesrgan required).

Tuning the design

Edit OPENROUTER_PROMPT.txt. The engine replaces {THEME_NOTE} with whatever the user types in the UI. Common tweaks:

  • Want denser pages? Add "no whitespace between elements" to the prompt.
  • Want a specific vibe? Add a single adjective to the THEME section: "luxurious", "minimalist", "playful".
  • Want different motifs? Replace the bullet list under "INTERIOR CONTENT".
  • Want crisper lines from the AI? The prompt ends with a "FINAL" line demanding vector-crisp output β€” edit it to make it more or less aggressive.

8K quality pipeline

The AI image comes back at whatever resolution OpenRouter returns (typically ~1024 px wide). The cover is composited on the top 1.5 in of a 600 DPI (3600Γ—5400 px) working canvas, then routed through a 4-pass sharpen chain:

  1. LANCZOS resize to the target resolution
  2. PIL.ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3)
  3. PIL.ImageFilter.SHARPEN (kernel sharpen)
  4. PIL.ImageEnhance.Sharpness(img).enhance(2.0)

The color palette is then quantized to 32 flat colors (posterize + quantize) for a true Adobe Illustrator look β€” no anti-aliased halos around flat-color regions. The result is embedded in the PDF as N full-bleed pages.

Vectorize mode (optional)

Setting VECTORIZE=1 in the Space's environment variables enables a potrace-based vector path that traces the line work to SVG and re-rasterizes at the target DPI for pixel-perfect lines. Requires the potrace system binary. Falls back gracefully to the raster path if potrace is missing.

Limitations

  • All pages are identical. Variation across pages is not supported in V8 (one image, repeated N times).
  • The AI does not see the cover image. It only sees the text theme note. The cover is stamped in post-production.
  • Pillow-only upscaling. For ultra-high-fidelity, replace _upscale_to_print in engine.py with a Real-ESRGAN call (will require PyTorch β€” won't fit HF Spaces free tier).
  • The default render is 600 DPI raster (4x the V8 baseline). For perfect vector lines, set VECTORIZE=1 in the Space's environment variables (requires potrace).

Security

  • Never commit .streamlit/secrets.toml or any file containing an API key. The included .gitignore blocks this.
  • Rotate any key that has been shared.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support