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>
74 lines
3.4 KiB
Docker
74 lines
3.4 KiB
Docker
# Build wymaga submodułu vendor/Rex-EMoolator — composite build kompiluje :core
|
|
# ze źródeł. Jeśli katalog jest pusty, settings.gradle przerwie z komunikatem.
|
|
FROM eclipse-temurin:21-jdk AS build
|
|
WORKDIR /src
|
|
|
|
# najpierw sam opis buildu: zmiana w kodzie nie unieważnia pobranych zależności
|
|
COPY gradlew settings.gradle build.gradle gradle.properties ./
|
|
COPY gradle ./gradle
|
|
COPY vendor ./vendor
|
|
RUN ./gradlew --no-daemon dependencies --configuration runtimeClasspath > /dev/null 2>&1 || true
|
|
|
|
COPY src ./src
|
|
# installDist zamiast build: pomija check, a więc i verifyCoreVersion, które
|
|
# potrzebowałoby gita w obrazie. Wersję i tak przypina submoduł.
|
|
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.
|
|
#
|
|
# 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)" \
|
|
&& 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
|
|
WORKDIR /app
|
|
|
|
# obrazy płyt montowane z zewnątrz, tylko do odczytu; katalog danych to wolumen
|
|
VOLUME ["/data"]
|
|
|
|
# whisper.cpp i ffmpeg wchodzą do obrazu, bo to kilkadziesiąt megabajtów.
|
|
# Model NIE wchodzi: waży kilkaset megabajtów do kilku gigabajtów, każdy trzyma
|
|
# inny i wybór należy do użytkownika — montuje się go pod /models i wskazuje
|
|
# przez WHISPER_MODEL. Bez modelu katalog działa normalnie, a front mówi wprost,
|
|
# czego brakuje: mówcę i kontekst kwestii bierzemy z dialogi.dta, nie z modelu.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends ffmpeg \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
# 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
|
|
# to samo, ale JVM wypisuje wtedy "Picked up..." przy każdym uruchomieniu
|
|
ENV CATALOG_DATA=/data
|
|
|
|
COPY --from=build /src/build/install/rex-catalog /app
|
|
COPY --from=build /src/core-version /app/core-version
|
|
COPY docker-entrypoint.sh /app/entrypoint.sh
|
|
RUN chmod +x /app/entrypoint.sh \
|
|
&& useradd --uid 10001 --create-home katalog \
|
|
&& mkdir -p /data /media \
|
|
&& chown katalog:katalog /data
|
|
USER katalog
|
|
|
|
EXPOSE 8765
|
|
ENTRYPOINT ["/app/entrypoint.sh"]
|
|
# domyślnie wstajemy jako serwer; front i MCP dzielą port
|
|
CMD ["serve", "--host", "0.0.0.0"]
|