tts-voice-creator-clone-and.../Dockerfile
mARTin-B78 736aeaaeac feat: add magazine projects with layout-aware article extraction
Magazines break the audiobook pipeline's assumptions: several unrelated
articles share a page, columns run in parallel, adverts and sidebars
interrupt body copy, and a feature routinely jumps twenty pages to its
tail. Narrating page-by-page walks out of an article mid-sentence and
into an advert, so the canonical object is the article, not the page.

core/magazine.py reconstructs articles from a flat PDF: PyMuPDF extracts
blocks with bboxes and font metrics, tesseract supplies a TSV fallback so
scanned pages join the same column grouping, blocks are classified and
ordered column-major, and articles are anchored by the parsed table of
contents with "continued on page N" tails linked back.

routes/magazine.py adds 13 endpoints. Ingestion is a restart-safe
background job. Nothing is narrated until a human approves the
boundaries; podcast generation refuses unapproved articles.

Podcast mode renders an approved article as a 2-3 host discussion using
the configured LLM and voices the user picks, alongside narration rather
than instead of it.

Verified end-to-end over HTTP on a synthetic 8-page issue: the feature
came back as pages [3, 8] with its jump tail absorbed and the advert page
excluded, and an image-only rendering recovered all 47 blocks via OCR.
44 new tests; full suite 90 passing.

The Studio UI is not built — this is reachable only via the API.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:46:54 +02:00

66 lines
3.8 KiB
Docker

# ─────────────────────────────────────────────────────────────────────────────
# TTS Voice Creator - Clone and Design — Docker image (ARM64 / aarch64 compatible)
#
# Web app (FastAPI + WaveSurfer.js) — no VNC, no Qt, no X11.
# Accessible on port 7890 via any browser.
# ─────────────────────────────────────────────────────────────────────────────
FROM python:3.11-slim-bookworm
ENV DEBIAN_FRONTEND=noninteractive
ENV PYTHONUNBUFFERED=1
# ── System packages ───────────────────────────────────────────────────────────
# libatomic1: pedalboard's native extension (pedalboard_native) links against
# libatomic.so.1 and fails to import without it — pip installs the Python
# package fine, but the C extension silently can't load at runtime.
# tesseract-ocr: server-side OCR fallback for scanned magazine pages. The TSV
# output carries word bounding boxes, which merge with PyMuPDF's block bboxes —
# plain text alone would lose the column/region structure magazine layout
# analysis depends on. deu/eng match the languages the client-side heading OCR
# already ships.
RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg \
curl \
ca-certificates \
libatomic1 \
tesseract-ocr \
tesseract-ocr-deu \
tesseract-ocr-eng \
&& rm -rf /var/lib/apt/lists/*
# ── Python dependencies ───────────────────────────────────────────────────────
COPY requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt
# ── Application ───────────────────────────────────────────────────────────────
WORKDIR /app
COPY server.py .
COPY CHANGELOG.md .
COPY VERSION .
COPY core/ core/
COPY routes/ routes/
COPY workflows/ workflows/
COPY static/ static/
# ── Vendor Tesseract.js (client-side OCR for image-based PDF chapter headings) ─
# Skipped if already present (e.g. bind-mounted from host during development).
RUN [ -f static/js/tesseract/tesseract.min.js ] || ( \
mkdir -p static/js/tesseract/lang && \
curl -sL -o static/js/tesseract/tesseract.min.js "https://unpkg.com/tesseract.js@5.1.1/dist/tesseract.min.js" && \
curl -sL -o static/js/tesseract/worker.min.js "https://unpkg.com/tesseract.js@5.1.1/dist/worker.min.js" && \
curl -sL -o static/js/tesseract/tesseract-core-simd-lstm.wasm.js "https://unpkg.com/tesseract.js-core@5.1.1/tesseract-core-simd-lstm.wasm.js" && \
curl -sL -o static/js/tesseract/tesseract-core-simd-lstm.wasm "https://unpkg.com/tesseract.js-core@5.1.1/tesseract-core-simd-lstm.wasm" && \
curl -sL -o static/js/tesseract/lang/deu.traineddata.gz "https://tessdata.projectnaptha.com/4.0.0_fast/deu.traineddata.gz" && \
curl -sL -o static/js/tesseract/lang/eng.traineddata.gz "https://tessdata.projectnaptha.com/4.0.0_fast/eng.traineddata.gz" \
)
# ── Runtime user ──────────────────────────────────────────────────────────────
RUN mkdir -p /voices/active_voices /voices/hidden_voices /home/app/.config/tts-voice-creator && \
useradd -m -s /bin/bash app && \
chown -R app:app /app /voices /home/app
USER app
EXPOSE 7890
CMD ["python3", "server.py"]