Build whisper.cpp into the image and mount the model from outside

Baking the model in was the wrong call: it is the part that weighs gigabytes,
everyone keeps a different one, and it has no business inside an image. The
binary is the opposite — whisper.cpp plus its libraries come to 2 MB. So the
tools go in and the model is mounted under /models, pointed at by WHISPER_MODEL.

Two things had to be worked out to build it. ggml tunes for the building
machine's CPU by default, which on arm64 emits -mcpu=native+nodotprod+noi8mm+nosve
and GCC 12 rejects outright; GGML_NATIVE=OFF fixes that and is what a portable
image wants anyway. And `cmake --install` insists on installing every example,
including binaries we deliberately did not build, so the artefacts are copied
straight out of the build tree.

A missing model is now reported before any work starts, not hit halfway through:
in a container the path is supplied from outside and the file behind it may
simply not be there.

Verified on the running daemon: image builds, and inside the container the full
pipeline reproduces the host run exactly — 13 copies, 880 scripts, 13 884
recordings, 3531 images and 6928 animations (81 515 frames). Graphics decode in
the container too, since the JRE image carries java.desktop. Thumbnails and
on-demand frame rendering answer over the published port, MCP lists 9 tools, the
collection mount rejects writes, the process runs as uid 10001, and data survives
a restart. The transcription chain was exercised with a stub binary in place of
whisper-cli: ffmpeg hands it exactly 16 kHz mono and results reach the database.
Only a real model run remains untried, since no model was downloaded.

Note on size: the image goes from 516 MB to 1.09 GB, and ffmpeg alone accounts
for 410 MB of that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Patryk Gensch
2026-08-21 15:11:31 +02:00
co-authored by Claude Opus 5
parent f1b36f0e29
commit cf6fd4e55e
2 changed files with 17 additions and 5 deletions
+3
View File
@@ -7,3 +7,6 @@ out/
# baza i cache pochodnych — generowane, nie wersjonowane
data/
# modele whisper.cpp montowane do kontenera — kilkaset MB, nie wersjonujemy
models/
+14 -5
View File
@@ -16,14 +16,22 @@ RUN ./gradlew --no-daemon installDist \
&& grep '^coreVersion=' gradle.properties | cut -d= -f2 > /src/core-version
# whisper.cpp budowany ze źródeł: w repozytoriach Debiana go nie ma, a binarka
# z hosta jest nie do użycia — tam macOS, tu Linux
# z hosta jest nie do użycia — tam macOS, tu Linux.
#
# GGML_NATIVE=OFF, bo domyślnie ggml stroi kod pod procesor maszyny budującej
# (na arm64 przekazuje -mcpu=native+nodotprod..., czego GCC 12 nie rozumie),
# a obraz i tak ma chodzić także na innym sprzęcie niż ten, na którym powstał
FROM debian:bookworm-slim AS whisper
RUN apt-get update \
&& apt-get install -y --no-install-recommends git cmake build-essential ca-certificates \
&& git clone --depth 1 --branch v1.7.4 https://github.com/ggerganov/whisper.cpp /src \
&& cmake -S /src -B /src/build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON \
-DGGML_NATIVE=OFF -DWHISPER_BUILD_TESTS=OFF -DWHISPER_BUILD_EXAMPLES=ON \
&& cmake --build /src/build --target whisper-cli -j "$(nproc)" \
&& cmake --install /src/build \
&& mkdir -p /out/bin /out/lib \
&& cp /src/build/bin/whisper-cli /out/bin/ \
&& find /src/build \( -name 'libwhisper.so*' -o -name 'libggml*.so' \) \
-exec cp -P {} /out/lib/ \; \
&& rm -rf /var/lib/apt/lists/* /src
FROM eclipse-temurin:21-jre
@@ -40,9 +48,10 @@ VOLUME ["/data"]
RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg \
&& rm -rf /var/lib/apt/lists/*
COPY --from=whisper /usr/local/bin/whisper-cli /usr/local/bin/whisper-cli
COPY --from=whisper /usr/local/lib/libwhisper.so* /usr/local/lib/
COPY --from=whisper /usr/local/lib/libggml*.so /usr/local/lib/
# kopiujemy wprost z drzewa budowania: `cmake --install` chciałby zainstalować
# wszystkie przykłady, a budujemy tylko whisper-cli
COPY --from=whisper /out/bin/whisper-cli /usr/local/bin/whisper-cli
COPY --from=whisper /out/lib/ /usr/local/lib/
RUN ldconfig
ENV WHISPER_BIN=/usr/local/bin/whisper-cli
# file.encoding ustawia entrypoint przez JAVA_OPTS; JAVA_TOOL_OPTIONS robiłoby