Files
pf-ocr/epub_builder/README.md
Poison Flower 35b7be680e feat(ocr): unify config, add manga translation pipeline and context lookahead
- Consolidate module configs into root config.example.json with ocr, vision, and epub sections

- Split LLM OCR workflows into novel_ocr.py (prose) and manga_ocr_llm.py (manga)

- Remove gemini_direct_ocr.py in favor of OpenAI-compatible API endpoints

- Support direct manga translation via --translate, --target-lang, and glossary.md

- Add bidirectional context support: past translations (--context-pages) and lookahead Japanese text (--context-pages-ahead)

- Add per-page JSON audit logging under logs/ and expose OpenAI sampling parameters
2026-09-06 15:42:29 +03:00

189 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# EPUB builder module
Assembles a `chapters/` folder — laid out by hand into per-chapter
subfolders — into a finished, valid `.epub`, with furigana rendered as
proper `<ruby>` markup, an embedded font, a cover image, and metadata from
the `epub` section of the repo's root `config.json`.
This is step 2 of the pipeline; step 1 is the [`ocr`](../ocr/README.md)
module, which produces the per-page `.txt` files you'll sort into
`chapters/`.
## Layout
```
config.json <- shared with the ocr module; see below for the "epub" section
epub_builder/
chapters/
cover.jpg <- cover image (optional, any "cover.*" directly in chapters/)
ch00_frontmatter/ <- everything before the main text (title page, TOC, ...)
001.txt
002.jpg
ch01_chapter00/
003.txt
004.txt
005.jpg
ch02_chapter01/
006.txt
ch08_backmatter/ <- everything after the main text (afterword, ...)
...
font/
YourFont.ttf <- font to embed (optional)
build_epub.py
furigana.py
```
## Chapter folder naming: `chNN_name`
- `chNN` — sequence number, determines sort order (`ch00``ch01` → ... →
`ch10`; use leading zeros if you have more than 9 chapters so plain
alphabetical sort stays correct).
- `name` — default chapter title (override via `config.json`'s
`epub.chapter_titles`).
- Folders with `frontmatter` or `backmatter` anywhere in their name are
**always** ignored: no title, no TOC entry — regardless of any flag or
config setting. Their content is still included in the book, just
without a section label.
Files inside a folder are sorted strictly by the number in the filename
(extension doesn't matter — an image `004.jpg` will land between
`003.txt` and `005.txt`).
## Page layout
- The first line of each `.txt` page (after stripping a leading page
number) is rendered as a larger, bold "page header" — typically an
in-story date/time/chapter marker (relevant if you're OCR-ing a novel
where that detail matters to the plot, e.g. one involving time travel).
- If nothing is left after stripping the page number, two blank lines are
shown instead, so the page's vertical rhythm stays consistent.
- A blank line always follows the header, then the text.
- Each paragraph starts with a full-width space (` `) — the standard
indent in Japanese typography, embedded directly in the text rather than
relying on CSS `text-indent` (which not every reader honors).
## config.json
This module reads the `epub` section of the shared `config.json` at the
repo root (copy `config.example.json` there if you haven't already):
```json
{
"epub": {
"title": "Your Book Title",
"author": "Author Name",
"language": "ja",
"identifier": "",
"publisher": "",
"description": "",
"date": "",
"rights": "",
"series": "",
"series_index": "",
"font_family": "",
"vertical": false,
"show_chapter_titles": false,
"output": "book.epub",
"chapter_titles": {
"ch00_frontmatter": "",
"ch01_chapter00": "Chapter 00",
"ch08_backmatter": ""
}
}
}
```
- `title`, `author`, `language` — core metadata (`title` is required).
- `identifier`, `publisher`, `description`, `date`, `rights` — optional
Dublin Core metadata, only added if non-empty. Leave `identifier` empty
to get a random UUID generated on every build; set it once and keep it
stable if you plan to rebuild the file repeatedly and want reading apps
to recognize it as the same book.
- `series` / `series_index` — Calibre-style series metadata
(`calibre:series` / `calibre:series_index`), recognized by Calibre,
KOReader, and several other reading apps.
- `font_family` — explicit name for the embedded font family (see "Font"
below). Optional — without it, the name is guessed automatically.
- `vertical` — vertical Japanese writing-mode (also toggleable via
`--vertical`).
- `show_chapter_titles` — whether to print the chapter title (`<h1>`) at
the start of each chapter. Defaults to `false` — titles still show up in
the table of contents either way. Toggle via `--show-chapter-titles`.
- `output` — path for the resulting epub, used if `--output` isn't passed.
- `chapter_titles` — folder name -> display title mapping. An empty string
`""` means "no heading, no TOC entry" (this is already the default
behavior for `frontmatter`/`backmatter` folders, so listing them here is
optional, just for clarity).
`frontmatter`/`backmatter` entries in `chapter_titles` are ignored no
matter what — they can't be "turned back on" via config.
## Font
Drop font file(s) (`.ttf`/`.otf`/`.woff`/`.woff2`) into `font/`. Name them
`Regular.ttf` / `Bold.ttf` / `Italic.ttf` / `BoldItalic.ttf` (case
doesn't matter, and the keyword can be part of a longer name, e.g.
`NotoSerifJP-Bold.ttf`) and they'll automatically be unified under one
font-family name with the correct `font-weight`/`font-style`. That means a
bold chapter heading (`<h1>`, and the page-header line) will automatically
pick up `Bold.ttf`, and italics (`<em>`), if any ever show up in the text,
will pick up `Italic.ttf`.
If the filenames don't match this pattern, the old behavior kicks in:
each file gets its own font-family name, and only the first one
(alphabetically) is wired up automatically in `body { font-family }`; the
rest are still embedded in the epub but need manual CSS edits to use.
The script tries to guess a shared family name from the common part of the
filenames (e.g. `NotoSerifJP-Regular.ttf` + `NotoSerifJP-Bold.ttf` ->
`NotoSerifJP`). To set it explicitly, use `config.json`'s `epub` section:
```json
{ "epub": { "font_family": "MyBookFont" } }
```
**Check the font's license** before embedding it in a file you intend to
share or publish — personal use on your own devices is usually fine, but
redistribution terms vary by font.
## Running
Simplest case — no arguments, if everything is where it's expected
(`config.json` one level up, at the repo root):
```bash
python build_epub.py
```
Or with explicit paths/overrides:
```bash
python build_epub.py \
--pages-dir ./chapters \
--font-dir ./font \
--config ../config.json \
--output ./my_book.epub \
--show-chapter-titles \
--vertical
```
`--split-pages` makes each file its own xhtml document inside the epub,
instead of merging every file in a folder into one.
## `furigana.py` as a standalone preview tool
Useful for quickly checking how a single OCR'd page will render before
running the full build:
```bash
python furigana.py --input page.txt --output preview.xhtml
# or a quick one-liner check:
echo "本文《ほんぶん》デザイン" | python furigana.py --stdin
```
## Requirements
```bash
pip install natsort
```