- Add cover image CRUD endpoints: GET/POST/DELETE /api/projects/{id}/cover
- Add output generation endpoints: POST /api/projects/{id}/output/{format}
- Add cover image and output queue service methods
- Add CoverImageResponse and CoverImageUploadResponse schemas
- Add umbra-api.js request handling for FormData (cover uploads)
- Add output generation buttons (EPUB/PDF/Audio) to Format UI in umbra-app.js
- Add backtranslate.py tool for verifying translation quality via back-translation
- Add cover image support to render.py EPUB generation
- Copy cover image to deal-hunter-zh source directory
- Spanish translation pipeline started (running in background)
Deal Hunter Chinese translation tools
This directory contains the translation and rendering pipeline used to produce the Simplified Chinese edition of Deal Hunter. It is deliberately separate from the web application: the book text and the translations are copyrighted and are not committed to this repository.
Where the data lives
productions/deal-hunter-zh/ # git-ignored
source/book.json # extracted English source model
glossary/glossary.json # names, places, terms, style rules
runs/<chapter>/*.json # analyses, drafts, critiques, final text
runs/usage.jsonl # per-call token/latency log
output/*.asciidoc, *.odt, *.pdf # review artefacts
The source bundle is the UmbraAudio controller bundle:
/home/umbra/audio-read/bundles/dh-bundle/manifest.jsonl
Its sha256 is recorded in Status.txt and in source/book.json.
Passes
| Pass | What it does | Model |
|---|---|---|
| 0 | Paragraph/scene/chunk assembly; keeps source utterance indices | none |
| 1 | Scene intent: summary, register, tone, participants, risks | lfm2.5-2.6b |
| 2 | Context-aware draft translation with glossary and analysis | qwen3.5-9b |
| 3 | Chapter voice/term consistency (optional) | critic model |
| 4 | Bilingual critic: meaning, pronoun, irony, term, omission | deepseek-r1-8b, fallback qwen3.5-9b |
Every analysis, draft and critique is a file under runs/<chapter>/. A run can
be stopped and resumed; existing artefacts are reused unless --force is
given. LLM responses are cached by prompt hash, so editing a prompt
invalidates the old answer.
The drafter is told to translate intent, not words, and is given a glossary, character voices, the scene analysis, and the previous chunk's summary. The critic uses a different model and returns a severity-sorted issue list; it does not rewrite the text.
Commands
Extract the source:
python3 tools/translation/book.py \
--out productions/deal-hunter-zh/source/book.json
Translate a chapter:
python3 tools/translation/pipeline.py \
--book productions/deal-hunter-zh/source/book.json \
--glossary productions/deal-hunter-zh/glossary/glossary.json \
--run-dir productions/deal-hunter-zh/runs \
--chapters ch-6
Selectors: all, front, body, back, or a comma-separated list of
chapter indices / ids / titles (-4,-3,-2,-1 must be quoted or passed as
--chapters=-4,-3).
Render:
python3 tools/translation/render.py \
--book productions/deal-hunter-zh/source/book.json \
--run-dir productions/deal-hunter-zh/runs \
--out-dir productions/deal-hunter-zh/output \
--sample
Mechanical QA:
python3 tools/translation/qa.py \
--book productions/deal-hunter-zh/source/book.json \
--run-dir productions/deal-hunter-zh/runs \
--json-out productions/deal-hunter-zh/runs/qa.json \
--strict
Models
The default server is the LAN LM Studio instance at
http://192.168.123.16:1234/v1. Override with:
UMBRA_TRANSLATION_BASE_URL
UMBRA_TRANSLATION_MODEL
UMBRA_TRANSLATION_ANALYST_MODEL
UMBRA_TRANSLATION_CRITIC_MODEL
Qwen models emit reasoning tokens by default; the client sends
reasoning_effort: "none" so the budget is spent on the translation. The small
analyst model rejects LM Studio's JSON-schema grammar, so its answer is parsed
from text and repaired if necessary.
Rendering
The AsciiDoc file is the canonical text output. The ODT is produced from a Flat
ODF document (.fodt) so that page layout, styles and the table of contents are
under our control. LibreOffice converts it and updates the TOC through UNO; a
plain --convert-to leaves the index empty. A PDF is exported for quick review.
Front matter, body and back matter use different styles. Chapter headings use
Chinese numerals (第一章 打捞). Body text is 11 pt Noto Serif CJK SC with
1.5 line spacing and a two-character first-line indent.
What this is not
- It is not a native-speaker-reviewed translation. The critic and the QA script catch mechanical defects; a human editor is still required.
- It does not recover the original DOCX paragraphing. The bundle is sentence-level, so paragraphs are reconstructed and can be reviewed.
- It does not produce a 1:1 utterance alignment for TTS. Source ranges are preserved on every paragraph; splitting or aligning back to the 4,319 utterances is a separate pass.