Files
rex-catalog/Dockerfile
T
Patryk GenschandClaude Opus 5 930cfb3462 Transcribe in batches instead of one file per whisper run
Every whisper.cpp invocation loads the model from scratch, which for a large
model takes longer than recognising a few seconds of speech. Running it once per
file meant that across seventeen thousand recordings the loading would dominate
the work entirely. Files now go in batches of sixteen — 40 files took 3 runs
instead of 40 in a stub test, with each file still getting its own result.

A batch has to be one language, since -l applies to the whole invocation, so work
is grouped by the language derived from the wavs/<code>/ path. Results come back
as files next to the inputs (-otxt) rather than on stdout, because with several
files in one run stdout cannot be split per file. Cancellation now lands between
batches rather than between files, which at sixteen files is close enough.

Thread count is left at whisper's own default and exposed as
catalog.whisper.threads: raising it buys speed at the cost of heat, and on a
fanless machine that turns into throttling anyway.

Docker: whisper.cpp bumped to v1.9.2 to match what Homebrew installs. The library
naming changed there — versioned sonames like libggml.so.0 — and the copy pattern
had to widen to match, otherwise the binary could not start.

Verified with a stub in place of whisper-cli, on the host and inside the
container: batching holds, each file gets its own text, and the temp directory
works as uid 10001. Nothing was left in the transcript table.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 16:06:08 +02:00

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.9.2 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"]