snapshot of https://github.com/ggml-org/whisper.cpp.git @ da54572229bcf64ba367d96c7ef15770376c4280 (2026-09-15)
Some checks failed
Bindings Tests (Go) / ubuntu-22 (push) Failing after 31s
CI (sycl) / ubuntu-22-cmake-sycl (linux/arm/v7, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl (linux/ppc64le, icx, icpx, ON) (push) Failing after 2s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/amd64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/arm/v7, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/arm64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/ppc64le, icx, icpx, ON) (push) Failing after 3s
CI (vad) / vad (push) Failing after 3s
CI (wasm) / emscripten (Release) (push) Failing after 4s
Bindings Tests (Ruby) / ubuntu-22 (push) Failing after 37s
CI (android) / android (push) Failing after 16s
CI (android) / android_java (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/amd64, Debug) (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/amd64, Release) (push) Failing after 2s
CI (clang) / ubuntu-22-clang (linux/ppc64le, Debug) (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/ppc64le, Release) (push) Failing after 3s
CI (cpu) / ggml-ci-x64-cpu-low-perf (push) Failing after 3s
CI (cpu) / ggml-ci-x64-cpu-high-perf (push) Failing after 2s
CI (gcc) / ubuntu-22-gcc (linux/amd64, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/amd64, Release) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/ppc64le, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/ppc64le, Release) (push) Failing after 4s
CI (gcc) / ubuntu-22-gcc-arm-v7 (linux/arm/v7, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc-arm-v7 (linux/arm/v7, Release) (push) Failing after 3s
CI (quantize) / quantize (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (ADDRESS) (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (THREAD) (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (UNDEFINED) (push) Failing after 2s
CI (sycl) / ubuntu-22-cmake-sycl (linux/amd64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl (linux/arm64, icx, icpx, ON) (push) Failing after 3s
Examples WASM / deploy-wasm-github-pages (push) Failing after 3s
Examples Tests / addon_node-ubuntu-22 (20.x) (push) Failing after 3s
Examples Tests / addon_node-ubuntu-22 (22.x) (push) Failing after 2s
CI (coreml) / coreml-base-en (push) Has been cancelled
CI (self-hosted) / gpu-vulkan (push) Has been cancelled
CI (self-hosted) / npu-amd-windows (push) Has been cancelled
CI (self-hosted) / gpu-vulkan-nvidia-cm2 (push) Has been cancelled
CI (clang) / ubuntu-22-clang-arm64 (Debug) (push) Has been cancelled
CI (clang) / ubuntu-22-clang-arm64 (Release) (push) Has been cancelled
CI (self-hosted) / gpu-cuda (push) Has been cancelled
CI (self-hosted) / gpu-vulkan-nvidia-cm (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-low-perf (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-high-perf (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-high-perf-sve (push) Has been cancelled
CI (freebsd) / freeBSD-latest (push) Has been cancelled
CI (self-hosted) / gpu-metal (push) Has been cancelled
CI (gcc) / ubuntu-22-gcc-arm64 (Debug) (push) Has been cancelled
CI (gcc) / ubuntu-22-gcc-arm64 (Release) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=iOS) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=macOS) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=tvOS) (push) Has been cancelled
CI (self-hosted) / npu-amd-linux (push) Has been cancelled
CI (windows) / windows-msys2 (Release, clang, clang-x86_64, CLANG64) (push) Has been cancelled
CI (windows) / windows-msys2 (Release, gcc, ucrt-x86_64, UCRT64) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-cuda.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-cuda]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-intel.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-intel]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-musa.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-musa]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-vulkan.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-vulkan]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-vulkan.Dockerfile platform:linux/arm64 runs_on:ubuntu-24.04-arm tag:main-vulkan-arm64]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main.Dockerfile platform:linux/arm64 runs_on:ubuntu-24.04-arm tag:main-arm64]) (push) Has been cancelled
Mark inactive issues stale / mark-issues (push) Failing after 1s
Some checks failed
Bindings Tests (Go) / ubuntu-22 (push) Failing after 31s
CI (sycl) / ubuntu-22-cmake-sycl (linux/arm/v7, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl (linux/ppc64le, icx, icpx, ON) (push) Failing after 2s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/amd64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/arm/v7, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/arm64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl-fp16 (linux/ppc64le, icx, icpx, ON) (push) Failing after 3s
CI (vad) / vad (push) Failing after 3s
CI (wasm) / emscripten (Release) (push) Failing after 4s
Bindings Tests (Ruby) / ubuntu-22 (push) Failing after 37s
CI (android) / android (push) Failing after 16s
CI (android) / android_java (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/amd64, Debug) (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/amd64, Release) (push) Failing after 2s
CI (clang) / ubuntu-22-clang (linux/ppc64le, Debug) (push) Failing after 3s
CI (clang) / ubuntu-22-clang (linux/ppc64le, Release) (push) Failing after 3s
CI (cpu) / ggml-ci-x64-cpu-low-perf (push) Failing after 3s
CI (cpu) / ggml-ci-x64-cpu-high-perf (push) Failing after 2s
CI (gcc) / ubuntu-22-gcc (linux/amd64, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/amd64, Release) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/ppc64le, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc (linux/ppc64le, Release) (push) Failing after 4s
CI (gcc) / ubuntu-22-gcc-arm-v7 (linux/arm/v7, Debug) (push) Failing after 3s
CI (gcc) / ubuntu-22-gcc-arm-v7 (linux/arm/v7, Release) (push) Failing after 3s
CI (quantize) / quantize (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (ADDRESS) (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (THREAD) (push) Failing after 3s
CI (sanitize) / ubuntu-22-gcc-sanitized (UNDEFINED) (push) Failing after 2s
CI (sycl) / ubuntu-22-cmake-sycl (linux/amd64, icx, icpx, ON) (push) Failing after 3s
CI (sycl) / ubuntu-22-cmake-sycl (linux/arm64, icx, icpx, ON) (push) Failing after 3s
Examples WASM / deploy-wasm-github-pages (push) Failing after 3s
Examples Tests / addon_node-ubuntu-22 (20.x) (push) Failing after 3s
Examples Tests / addon_node-ubuntu-22 (22.x) (push) Failing after 2s
CI (coreml) / coreml-base-en (push) Has been cancelled
CI (self-hosted) / gpu-vulkan (push) Has been cancelled
CI (self-hosted) / npu-amd-windows (push) Has been cancelled
CI (self-hosted) / gpu-vulkan-nvidia-cm2 (push) Has been cancelled
CI (clang) / ubuntu-22-clang-arm64 (Debug) (push) Has been cancelled
CI (clang) / ubuntu-22-clang-arm64 (Release) (push) Has been cancelled
CI (self-hosted) / gpu-cuda (push) Has been cancelled
CI (self-hosted) / gpu-vulkan-nvidia-cm (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-low-perf (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-high-perf (push) Has been cancelled
CI (cpu) / ggml-ci-arm64-cpu-high-perf-sve (push) Has been cancelled
CI (freebsd) / freeBSD-latest (push) Has been cancelled
CI (self-hosted) / gpu-metal (push) Has been cancelled
CI (gcc) / ubuntu-22-gcc-arm64 (Debug) (push) Has been cancelled
CI (gcc) / ubuntu-22-gcc-arm64 (Release) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=iOS) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=macOS) (push) Has been cancelled
CI (macOS) / macOS-latest (generic/platform=tvOS) (push) Has been cancelled
CI (self-hosted) / npu-amd-linux (push) Has been cancelled
CI (windows) / windows-msys2 (Release, clang, clang-x86_64, CLANG64) (push) Has been cancelled
CI (windows) / windows-msys2 (Release, gcc, ucrt-x86_64, UCRT64) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-cuda.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-cuda]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-intel.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-intel]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-musa.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-musa]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-vulkan.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main-vulkan]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main-vulkan.Dockerfile platform:linux/arm64 runs_on:ubuntu-24.04-arm tag:main-vulkan-arm64]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main.Dockerfile platform:linux/amd64 runs_on:ubuntu-24.04 tag:main]) (push) Has been cancelled
Publish Docker image / Push Docker image to Docker Hub (map[dockerfile:.devops/main.Dockerfile platform:linux/arm64 runs_on:ubuntu-24.04-arm tag:main-arm64]) (push) Has been cancelled
Mark inactive issues stale / mark-issues (push) Failing after 1s
This commit is contained in:
28
.devops/cublas.Dockerfile
Normal file
28
.devops/cublas.Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
ARG UBUNTU_VERSION=22.04
|
||||||
|
|
||||||
|
# This needs to generally match the container host's environment.
|
||||||
|
ARG CUDA_VERSION=11.7.1
|
||||||
|
|
||||||
|
# Target the CUDA build image
|
||||||
|
ARG BASE_CUDA_DEV_CONTAINER=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION}
|
||||||
|
|
||||||
|
FROM ${BASE_CUDA_DEV_CONTAINER} as build
|
||||||
|
|
||||||
|
# Unless otherwise specified, we make a fat build.
|
||||||
|
ARG CUDA_DOCKER_ARCH=all
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential git cmake libsdl2-dev wget git
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Set nvcc architecture
|
||||||
|
ENV CUDA_DOCKER_ARCH=${CUDA_DOCKER_ARCH}
|
||||||
|
# Enable cuBLAS
|
||||||
|
ENV GGML_CUDA=1
|
||||||
|
|
||||||
|
RUN make base.en
|
||||||
|
|
||||||
|
ENTRYPOINT ["/app/main"]
|
||||||
50
.devops/main-cuda.Dockerfile
Normal file
50
.devops/main-cuda.Dockerfile
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
ARG UBUNTU_VERSION=22.04
|
||||||
|
# This needs to generally match the container host's environment.
|
||||||
|
ARG CUDA_VERSION=13.0.0
|
||||||
|
# Target the CUDA build image
|
||||||
|
ARG BASE_CUDA_DEV_CONTAINER=nvidia/cuda:${CUDA_VERSION}-devel-ubuntu${UBUNTU_VERSION}
|
||||||
|
# Target the CUDA runtime image
|
||||||
|
ARG BASE_CUDA_RUN_CONTAINER=nvidia/cuda:${CUDA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}
|
||||||
|
|
||||||
|
FROM ${BASE_CUDA_DEV_CONTAINER} AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Unless otherwise specified, we make a fat build.
|
||||||
|
ARG CUDA_DOCKER_ARCH=all
|
||||||
|
# Set nvcc architecture
|
||||||
|
ENV CUDA_DOCKER_ARCH=${CUDA_DOCKER_ARCH}
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential libsdl2-dev wget cmake git \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
# The build stage has no real GPU/driver, so the linker needs the
|
||||||
|
# forward-compat libcuda stub to resolve CUDA driver-API symbols.
|
||||||
|
# Ref: https://stackoverflow.com/a/53464012
|
||||||
|
ENV CUDA_MAIN_VERSION=13.0
|
||||||
|
ENV LD_LIBRARY_PATH /usr/local/cuda-${CUDA_MAIN_VERSION}/compat:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
# Enable cuBLAS
|
||||||
|
RUN --mount=type=secret,id=HF_TOKEN,required=false,env=HF_TOKEN make base.en CMAKE_ARGS="-DGGML_CUDA=1 -DCMAKE_CUDA_ARCHITECTURES='75;80;86;90'"
|
||||||
|
|
||||||
|
RUN find /app/build -name "*.o" -delete && \
|
||||||
|
find /app/build -name "*.a" -delete && \
|
||||||
|
rm -rf /app/build/CMakeFiles && \
|
||||||
|
rm -rf /app/build/cmake_install.cmake && \
|
||||||
|
rm -rf /app/build/_deps
|
||||||
|
|
||||||
|
FROM ${BASE_CUDA_RUN_CONTAINER} AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl ffmpeg wget cmake git \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
RUN du -sh /app/*
|
||||||
|
RUN find /app -type f -size +100M
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
29
.devops/main-intel.Dockerfile
Normal file
29
.devops/main-intel.Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
ARG ONEAPI_VERSION=2025.3.3-0-devel-ubuntu24.04
|
||||||
|
|
||||||
|
FROM intel/deep-learning-essentials:$ONEAPI_VERSION AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential libsdl2-dev wget cmake git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
# Enable SYCL
|
||||||
|
ARG GGML_SYCL_F16=OFF
|
||||||
|
RUN --mount=type=secret,id=HF_TOKEN,required=false,env=HF_TOKEN \
|
||||||
|
if [ "${GGML_SYCL_F16}" = "ON" ]; then \
|
||||||
|
echo "GGML_SYCL_F16 is set" \
|
||||||
|
&& export OPT_SYCL_F16="-DGGML_SYCL_F16=ON"; \
|
||||||
|
fi && \
|
||||||
|
make base.en CMAKE_ARGS="-DGGML_SYCL=1 -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx ${OPT_SYCL_F16}"
|
||||||
|
|
||||||
|
FROM intel/deep-learning-essentials:$ONEAPI_VERSION AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl ffmpeg libsdl2-dev wget cmake git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
40
.devops/main-musa.Dockerfile
Normal file
40
.devops/main-musa.Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
ARG UBUNTU_VERSION=22.04
|
||||||
|
# This needs to generally match the container host's environment.
|
||||||
|
ARG MUSA_VERSION=rc4.2.0
|
||||||
|
# Target the MUSA build image
|
||||||
|
ARG BASE_MUSA_DEV_CONTAINER=mthreads/musa:${MUSA_VERSION}-devel-ubuntu${UBUNTU_VERSION}-amd64
|
||||||
|
# Target the MUSA runtime image
|
||||||
|
ARG BASE_MUSA_RUN_CONTAINER=mthreads/musa:${MUSA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}-amd64
|
||||||
|
|
||||||
|
FROM ${BASE_MUSA_DEV_CONTAINER} AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential libsdl2-dev wget cmake git && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
# Enable muBLAS
|
||||||
|
RUN --mount=type=secret,id=HF_TOKEN,required=false,env=HF_TOKEN make base.en CMAKE_ARGS="-DGGML_MUSA=1"
|
||||||
|
|
||||||
|
RUN find /app/build -name "*.o" -delete && \
|
||||||
|
find /app/build -name "*.a" -delete && \
|
||||||
|
rm -rf /app/build/CMakeFiles && \
|
||||||
|
rm -rf /app/build/cmake_install.cmake && \
|
||||||
|
rm -rf /app/build/_deps
|
||||||
|
|
||||||
|
FROM ${BASE_MUSA_RUN_CONTAINER} AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl ffmpeg wget cmake git && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/* /tmp/* /var/tmp/*
|
||||||
|
|
||||||
|
COPY --from=build /app/build/bin /app/build/bin
|
||||||
|
COPY --from=build /app/samples /app/samples
|
||||||
|
COPY --from=build /app/models /app/models
|
||||||
|
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
81
.devops/main-rocm.Dockerfile
Normal file
81
.devops/main-rocm.Dockerfile
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# build stage
|
||||||
|
FROM registry.fedoraproject.org/fedora:44 AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# ROCm 7.14 repository (TheRock release stream)
|
||||||
|
RUN <<'EOF'
|
||||||
|
tee /etc/yum.repos.d/rocm.repo <<REPO
|
||||||
|
[rocm]
|
||||||
|
name=ROCm 7.14.0
|
||||||
|
baseurl=https://repo.amd.com/rocm/packages-multi-arch/rhel10/x86_64
|
||||||
|
enabled=1
|
||||||
|
priority=50
|
||||||
|
gpgcheck=1
|
||||||
|
gpgkey=https://repo.amd.com/rocm/packages-multi-arch/gpg/rocm.gpg
|
||||||
|
REPO
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN dnf -y --nodocs --setopt=install_weak_deps=False \
|
||||||
|
install \
|
||||||
|
make gcc gcc-c++ cmake git ninja-build rdma-core-devel \
|
||||||
|
amdrocm-core-devel7.14-gfx1151 \
|
||||||
|
&& dnf clean all && rm -rf /var/cache/dnf/*
|
||||||
|
|
||||||
|
ENV ROCM_PATH=/opt/rocm \
|
||||||
|
HIP_PATH=/opt/rocm \
|
||||||
|
PATH=/opt/rocm/bin:/opt/rocm/core/bin:/opt/rocm/core/lib/llvm/bin:$PATH \
|
||||||
|
LD_LIBRARY_PATH=/opt/rocm/core/lib/rocm_sysdeps/lib:/opt/rocm/core/lib
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
RUN make base.en CMAKE_ARGS="-DGGML_HIP=1 -DAMDGPU_TARGETS=\"gfx1100;gfx1101;gfx1102;gfx1103;gfx1150;gfx1151;gfx1152;gfx1200;gfx1201\""
|
||||||
|
|
||||||
|
# runtime stage
|
||||||
|
FROM registry.fedoraproject.org/fedora-minimal:44 AS runtime
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# ROCm 7.14 repository (TheRock release stream)
|
||||||
|
RUN <<'EOF'
|
||||||
|
tee /etc/yum.repos.d/rocm.repo <<REPO
|
||||||
|
[rocm]
|
||||||
|
name=ROCm 7.14.0
|
||||||
|
baseurl=https://repo.amd.com/rocm/packages-multi-arch/rhel10/x86_64
|
||||||
|
enabled=1
|
||||||
|
priority=50
|
||||||
|
gpgcheck=1
|
||||||
|
gpgkey=https://repo.amd.com/rocm/packages-multi-arch/gpg/rocm.gpg
|
||||||
|
REPO
|
||||||
|
EOF
|
||||||
|
|
||||||
|
RUN microdnf -y --nodocs --setopt=install_weak_deps=0 \
|
||||||
|
install \
|
||||||
|
bash ca-certificates libatomic libstdc++ libgcc libgomp libibverbs \
|
||||||
|
amdrocm-runtime7.14 \
|
||||||
|
amdrocm-blas7.14-gfx1100 \
|
||||||
|
amdrocm-blas7.14-gfx1101 \
|
||||||
|
amdrocm-blas7.14-gfx1102 \
|
||||||
|
amdrocm-blas7.14-gfx1103 \
|
||||||
|
amdrocm-blas7.14-gfx1150 \
|
||||||
|
amdrocm-blas7.14-gfx1151 \
|
||||||
|
amdrocm-blas7.14-gfx1152 \
|
||||||
|
amdrocm-blas7.14-gfx1200 \
|
||||||
|
amdrocm-blas7.14-gfx1201 \
|
||||||
|
&& microdnf clean all && rm -rf /var/cache/dnf/* \
|
||||||
|
&& ln -s core-7.14 /opt/rocm/core \
|
||||||
|
&& ln -s core-7.14/bin /opt/rocm/bin \
|
||||||
|
&& ln -s core-7.14/include /opt/rocm/include \
|
||||||
|
&& ln -s core-7.14/lib /opt/rocm/lib \
|
||||||
|
&& ln -s core-7.14/libexec /opt/rocm/libexec \
|
||||||
|
&& ln -s core-7.14/lib/llvm /opt/rocm/llvm \
|
||||||
|
&& ln -s core-7.14/share /opt/rocm/share \
|
||||||
|
&& ln -s core-7.14/lib/llvm/amdgcn /opt/rocm/amdgcn
|
||||||
|
|
||||||
|
ENV ROCM_PATH=/opt/rocm \
|
||||||
|
HIP_PATH=/opt/rocm \
|
||||||
|
PATH=/opt/rocm/bin:/opt/rocm/core/bin:/opt/rocm/core/lib/llvm/bin:$PATH \
|
||||||
|
LD_LIBRARY_PATH=/opt/rocm/core/lib/rocm_sysdeps/lib:/opt/rocm/core/lib
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
20
.devops/main-vulkan.Dockerfile
Normal file
20
.devops/main-vulkan.Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
FROM ubuntu:24.04 AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential wget cmake git libvulkan-dev spirv-headers glslc \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
RUN --mount=type=secret,id=HF_TOKEN,required=false,env=HF_TOKEN make base.en CMAKE_ARGS="-DGGML_VULKAN=1"
|
||||||
|
|
||||||
|
FROM ubuntu:24.04 AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl ffmpeg libsdl2-dev wget cmake git libvulkan1 mesa-vulkan-drivers \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
20
.devops/main.Dockerfile
Normal file
20
.devops/main.Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
FROM ubuntu:22.04 AS build
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y build-essential wget cmake git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY .. .
|
||||||
|
RUN --mount=type=secret,id=HF_TOKEN,required=false,env=HF_TOKEN make base.en
|
||||||
|
|
||||||
|
FROM ubuntu:22.04 AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y curl ffmpeg libsdl2-dev wget cmake git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* /var/cache/apt/archives/*
|
||||||
|
|
||||||
|
COPY --from=build /app /app
|
||||||
|
ENV PATH=/app/build/bin:$PATH
|
||||||
|
ENTRYPOINT [ "bash", "-c" ]
|
||||||
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
build*/
|
||||||
|
.github/
|
||||||
|
.devops/
|
||||||
22
.github/actions/ccache-clear/action.yml
vendored
Normal file
22
.github/actions/ccache-clear/action.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: "ccache-clear"
|
||||||
|
description: "Delete all GitHub Actions caches matching a key prefix"
|
||||||
|
inputs:
|
||||||
|
key:
|
||||||
|
description: "Cache key prefix to match and delete"
|
||||||
|
required: true
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Clear caches
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
CACHES=$(gh cache list --key "ccache-${{ inputs.key }}" --json id,key --jq '.[] | "\(.id) \(.key)"' 2>/dev/null)
|
||||||
|
if [ -z "$CACHES" ]; then
|
||||||
|
echo "No caches found with key prefix: ${{ inputs.key }}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
while read -r id key; do
|
||||||
|
echo "Deleting cache: $id ($key)"
|
||||||
|
gh cache delete "$id"
|
||||||
|
done <<< "$CACHES"
|
||||||
22
.github/workflows/bindings-go.yml
vendored
Normal file
22
.github/workflows/bindings-go.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
name: Bindings Tests (Go)
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- bindings/go/**
|
||||||
|
- include/whisper.h
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- bindings/go/**
|
||||||
|
- include/whisper.h
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6
|
||||||
|
with:
|
||||||
|
go-version: '^1.23'
|
||||||
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
- run: |
|
||||||
|
cd bindings/go
|
||||||
|
make test
|
||||||
32
.github/workflows/bindings-ruby.yml
vendored
Normal file
32
.github/workflows/bindings-ruby.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Bindings Tests (Ruby)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- bindings/ruby/**
|
||||||
|
- include/whisper.h
|
||||||
|
- examples/common-whisper.h
|
||||||
|
- ggml/include/ggml.h
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths:
|
||||||
|
- bindings/ruby/**
|
||||||
|
- include/whisper.h
|
||||||
|
- examples/common-whisper.h
|
||||||
|
- ggml/include/ggml.h
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: bindings/ruby
|
||||||
|
steps:
|
||||||
|
- uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
|
||||||
|
with:
|
||||||
|
ruby-version: '3.3'
|
||||||
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
- run: rake test
|
||||||
80
.github/workflows/build-android.yml
vendored
Normal file
80
.github/workflows/build-android.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: CI (android)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-android.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.java']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
android:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
with:
|
||||||
|
path: whisper
|
||||||
|
|
||||||
|
- name: Install Java
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||||
|
with:
|
||||||
|
distribution: zulu
|
||||||
|
java-version: 21
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd whisper/examples/whisper.android
|
||||||
|
./gradlew assembleRelease --no-daemon
|
||||||
|
|
||||||
|
- name: Build with external ggml
|
||||||
|
run: |
|
||||||
|
export PATH_TO_GGML=$PWD/ggml
|
||||||
|
cd whisper/examples/whisper.android
|
||||||
|
./gradlew assembleRelease --no-daemon
|
||||||
|
|
||||||
|
android_java:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: set up JDK 11
|
||||||
|
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
|
||||||
|
with:
|
||||||
|
java-version: '11'
|
||||||
|
distribution: 'temurin'
|
||||||
|
cache: gradle
|
||||||
|
|
||||||
|
- name: Setup Android SDK
|
||||||
|
uses: android-actions/setup-android@40fd30fb8d7440372e1316f5d1809ec01dcd3699 # v4.0.1
|
||||||
|
with:
|
||||||
|
cmdline-tools-version: 9.0
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd examples/whisper.android.java
|
||||||
|
chmod +x ./gradlew
|
||||||
|
./gradlew assembleRelease
|
||||||
122
.github/workflows/build-clang.yml
vendored
Normal file
122
.github/workflows/build-clang.yml
vendored
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
name: CI (clang)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-clang.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.cl']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
ubuntu_image: "ubuntu:22.04"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22-clang:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Debug, Release]
|
||||||
|
#arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]
|
||||||
|
# TODO: arm/v7 disabled due to clang bug
|
||||||
|
# https://github.com/ggerganov/whisper.cpp/actions/runs/9657764109/job/26637633042?pr=2256#step:4:1990
|
||||||
|
arch: [linux/amd64, linux/ppc64le]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Set CCACHE_DIR
|
||||||
|
run: echo "CCACHE_DIR=${{ runner.temp }}/ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: clang-${{ matrix.arch }}-${{ matrix.build }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.arch }}
|
||||||
|
run: |
|
||||||
|
docker run --platform ${{ matrix.arch }} --rm \
|
||||||
|
-v ${{ github.workspace }}:/workspace \
|
||||||
|
-v ${CCACHE_DIR}:${CCACHE_DIR} \
|
||||||
|
-e CCACHE_DIR=${CCACHE_DIR} \
|
||||||
|
-w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
|
||||||
|
set -e
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sed -i "s|archive.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
sed -i "s|security.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt install -y clang build-essential cmake libsdl2-dev git ccache
|
||||||
|
cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++ \
|
||||||
|
-DCMAKE_C_COMPILER=clang \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DGGML_NATIVE=OFF
|
||||||
|
make
|
||||||
|
ctest -L gh --output-on-failure'
|
||||||
|
|
||||||
|
ubuntu-22-clang-arm64:
|
||||||
|
runs-on: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Debug, Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: clang-arm64-${{ matrix.build }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y clang build-essential cmake libsdl2-dev git
|
||||||
|
|
||||||
|
- name: Build and Test
|
||||||
|
run: |
|
||||||
|
cmake . -DWHISPER_SDL2=ON \
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DCMAKE_CXX_COMPILER=clang++ \
|
||||||
|
-DCMAKE_C_COMPILER=clang \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_CPU_ARM_ARCH=armv8-a
|
||||||
|
make
|
||||||
|
ctest -L gh --output-on-failure
|
||||||
65
.github/workflows/build-coreml.yml
vendored
Normal file
65
.github/workflows/build-coreml.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: CI (coreml)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
paths: ['.github/workflows/build-coreml.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.swift',
|
||||||
|
'**/*.m',
|
||||||
|
'**/*.mm',
|
||||||
|
'**/*.metal']
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
coreml-base-en:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout with full history
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set environment variables
|
||||||
|
id: set_vars
|
||||||
|
run: |
|
||||||
|
BUILD_NUMBER=$(git rev-list --count HEAD)
|
||||||
|
SHORT_HASH=$(git rev-parse --short=7 HEAD)
|
||||||
|
if [[ "${{ github.ref_type }}" == "tag" ]]; then
|
||||||
|
TAG_NAME="${{ github.ref_name }}"
|
||||||
|
elif [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
TAG_NAME="b${BUILD_NUMBER}"
|
||||||
|
else
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
TAG_NAME="${SAFE_NAME}-b${BUILD_NUMBER}-${SHORT_HASH}"
|
||||||
|
fi
|
||||||
|
echo "MODEL_NAME=base.en" >> $GITHUB_ENV
|
||||||
|
echo "GEN_MODEL_NAME=whisper-${TAG_NAME}-ggml-base.en-encoder.mlmodelc" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Download model
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
./models/download-ggml-model.sh ${{ env.MODEL_NAME }}
|
||||||
|
|
||||||
|
- name: Generate CoreML model
|
||||||
|
run: |
|
||||||
|
python3.11 -m venv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install ane_transformers openai-whisper coremltools
|
||||||
|
./models/generate-coreml-model.sh ${{ env.MODEL_NAME }}
|
||||||
173
.github/workflows/build-cpu.yml
vendored
Normal file
173
.github/workflows/build-cpu.yml
vendored
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
name: CI (cpu)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-cpu.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.cl']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
# TODO: simplify the following jobs using a matrix
|
||||||
|
jobs:
|
||||||
|
ggml-ci-x64-cpu-low-perf:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ggml-ci-x64-cpu-low-perf
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libcurl4-openssl-dev
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
LLAMA_ARG_THREADS=$(nproc) GG_BUILD_LOW_PERF=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
|
|
||||||
|
ggml-ci-arm64-cpu-low-perf:
|
||||||
|
runs-on: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ggml-ci-arm64-cpu-low-perf
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libcurl4-openssl-dev
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
LLAMA_ARG_THREADS=$(nproc) GG_BUILD_LOW_PERF=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
|
|
||||||
|
ggml-ci-x64-cpu-high-perf:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ggml-ci-x64-cpu-high-perf
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libcurl4-openssl-dev
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
LLAMA_ARG_THREADS=$(nproc) bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
|
|
||||||
|
ggml-ci-arm64-cpu-high-perf:
|
||||||
|
runs-on: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ggml-ci-arm64-cpu-high-perf
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libcurl4-openssl-dev
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
LLAMA_ARG_THREADS=$(nproc) GG_BUILD_NO_SVE=1 GG_BUILD_NO_BF16=1 GG_BUILD_EXTRA_TESTS_0=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
|
|
||||||
|
ggml-ci-arm64-cpu-high-perf-sve:
|
||||||
|
runs-on: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ggml-ci-arm64-cpu-high-perf-sve
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
id: depends
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential libcurl4-openssl-dev
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
LLAMA_ARG_THREADS=$(nproc) GG_BUILD_NO_BF16=1 GG_BUILD_EXTRA_TESTS_0=1 bash ./ci/run.sh ./tmp/results ./tmp/mnt
|
||||||
47
.github/workflows/build-freebsd.yml
vendored
Normal file
47
.github/workflows/build-freebsd.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: CI (freebsd)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-freebsd.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
freeBSD-latest:
|
||||||
|
runs-on: macos-13
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
uses: cross-platform-actions/action@fe0167d8082ac584754ef3ffb567fded22642c7d # v0.27.0
|
||||||
|
with:
|
||||||
|
operating_system: freebsd
|
||||||
|
version: '14.2'
|
||||||
|
run: |
|
||||||
|
sudo pkg update
|
||||||
|
sudo pkg install -y gmake sdl2 cmake git
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build --config Release
|
||||||
167
.github/workflows/build-gcc.yml
vendored
Normal file
167
.github/workflows/build-gcc.yml
vendored
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
name: CI (gcc)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-gcc.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.cl']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
ubuntu_image: "ubuntu:22.04"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22-gcc:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Debug, Release]
|
||||||
|
arch: [linux/amd64, linux/ppc64le]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Set CCACHE_DIR
|
||||||
|
run: echo "CCACHE_DIR=${{ runner.temp }}/ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: gcc-${{ matrix.arch }}-${{ matrix.build }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.arch }}
|
||||||
|
run: |
|
||||||
|
docker run --platform ${{ matrix.arch }} --rm \
|
||||||
|
-v ${{ github.workspace }}:/workspace \
|
||||||
|
-v ${CCACHE_DIR}:${CCACHE_DIR} \
|
||||||
|
-e CCACHE_DIR=${CCACHE_DIR} \
|
||||||
|
-w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
|
||||||
|
set -e
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sed -i "s|archive.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
sed -i "s|security.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt install -y build-essential cmake libsdl2-dev git ccache
|
||||||
|
cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
make
|
||||||
|
ctest -L gh --output-on-failure'
|
||||||
|
|
||||||
|
ubuntu-22-gcc-arm64:
|
||||||
|
runs-on: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Debug, Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: gcc-arm64-${{ matrix.build }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y build-essential cmake libsdl2-dev git
|
||||||
|
|
||||||
|
- name: Configure CMake
|
||||||
|
run: |
|
||||||
|
cmake . \
|
||||||
|
-DWHISPER_SDL2=ON \
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_CPU_ARM_ARCH=armv8-a
|
||||||
|
|
||||||
|
- name: Build and Test
|
||||||
|
run: |
|
||||||
|
make
|
||||||
|
ctest -L gh --output-on-failure
|
||||||
|
|
||||||
|
ubuntu-22-gcc-arm-v7:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Debug, Release]
|
||||||
|
arch: [linux/arm/v7]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Set CCACHE_DIR
|
||||||
|
run: echo "CCACHE_DIR=${{ runner.temp }}/ccache" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: gcc-${{ matrix.arch }}-${{ matrix.build }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Set up QEMU
|
||||||
|
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
|
||||||
|
|
||||||
|
- name: Build ${{ matrix.arch }}
|
||||||
|
run: |
|
||||||
|
docker run --platform ${{ matrix.arch }} --rm \
|
||||||
|
-v ${{ github.workspace }}:/workspace \
|
||||||
|
-v ${CCACHE_DIR}:${CCACHE_DIR} \
|
||||||
|
-e CCACHE_DIR=${CCACHE_DIR} \
|
||||||
|
-w /workspace ${{ env.ubuntu_image }} /bin/sh -c '
|
||||||
|
set -e
|
||||||
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
|
sed -i "s|archive.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
sed -i "s|security.ubuntu.com|mirrors.kernel.org|g" /etc/apt/sources.list
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt install -y build-essential cmake libsdl2-dev git ccache
|
||||||
|
cmake . -DWHISPER_SDL2=ON -DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_CPU_ARM_ARCH=armv7-a+fp \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
make
|
||||||
|
ctest -L gh --output-on-failure'
|
||||||
73
.github/workflows/build-macos.yml
vendored
Normal file
73
.github/workflows/build-macos.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: CI (macOS)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-macos.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.swift',
|
||||||
|
'**/*.m',
|
||||||
|
'**/*.mm',
|
||||||
|
'**/*.metal']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
macOS-latest:
|
||||||
|
runs-on: macOS-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
destination: ['generic/platform=macOS', 'generic/platform=iOS', 'generic/platform=tvOS']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: macos-${{ matrix.destination }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
cmake --version
|
||||||
|
brew install sdl2
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
sysctl -a
|
||||||
|
cmake -B build -G Xcode \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
|
-DWHISPER_BUILD_EXAMPLES=OFF \
|
||||||
|
-DWHISPER_BUILD_TESTS=OFF \
|
||||||
|
-DWHISPER_BUILD_SERVER=OFF \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64"
|
||||||
|
cmake --build build --config Release -j $(sysctl -n hw.logicalcpu)
|
||||||
48
.github/workflows/build-quantize.yml
vendored
Normal file
48
.github/workflows/build-quantize.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: CI (quantize)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-quantize.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
quantize:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: quantize-ubuntu-22
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Test quantize
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
./models/download-ggml-model.sh tiny.en
|
||||||
|
cmake -B build -DGGML_NATIVE=OFF -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||||
|
cmake --build build --config Release
|
||||||
|
./build/bin/whisper-quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0
|
||||||
85
.github/workflows/build-sanitize.yml
vendored
Normal file
85
.github/workflows/build-sanitize.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
name: CI (sanitize)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-sanitize.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**'
|
||||||
|
- 'bindings/go/**'
|
||||||
|
- 'examples/addon.node/**'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22-gcc-sanitized:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
sanitizer: [ADDRESS, THREAD, UNDEFINED]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: sanitize-${{ matrix.sanitizer }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y build-essential cmake git
|
||||||
|
|
||||||
|
- name: Build (undefined)
|
||||||
|
if: ${{ matrix.sanitizer == 'UNDEFINED' }}
|
||||||
|
run: |
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=Debug \
|
||||||
|
-DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_OPENMP=OFF
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
if: ${{ matrix.sanitizer == 'ADDRESS' }}
|
||||||
|
run: |
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON \
|
||||||
|
-DGGML_NATIVE=OFF
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Build (no OpenMP)
|
||||||
|
if: ${{ matrix.sanitizer == 'THREAD' }}
|
||||||
|
run: |
|
||||||
|
cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||||
|
-DWHISPER_SANITIZE_${{ matrix.sanitizer }}=ON \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DGGML_OPENMP=OFF
|
||||||
|
make
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
if: ${{ matrix.sanitizer != 'UNDEFINED' }}
|
||||||
|
run: |
|
||||||
|
ctest -L gh --output-on-failure
|
||||||
259
.github/workflows/build-self-hosted.yml
vendored
Normal file
259
.github/workflows/build-self-hosted.yml
vendored
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
name: CI (self-hosted)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: [
|
||||||
|
'.github/workflows/build.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/.cmake',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.swift',
|
||||||
|
'**/*.m',
|
||||||
|
'**/*.mm',
|
||||||
|
'**/*.metal',
|
||||||
|
'**/*.comp'
|
||||||
|
]
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths: [
|
||||||
|
'.github/workflows/build-self-hosted.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/.cmake',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.swift',
|
||||||
|
'**/*.m',
|
||||||
|
'**/*.mm',
|
||||||
|
'**/*.metal',
|
||||||
|
'**/*.comp'
|
||||||
|
]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
gpu-cuda:
|
||||||
|
runs-on: [self-hosted, Linux, NVIDIA]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
run: |
|
||||||
|
nvidia-smi
|
||||||
|
GG_BUILD_CUDA=1 bash ./ci/run.sh ~/results/whisper.cpp ~/mnt/whisper.cpp
|
||||||
|
|
||||||
|
gpu-vulkan-nvidia-cm:
|
||||||
|
runs-on: [self-hosted, Linux, NVIDIA]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
run: |
|
||||||
|
vulkaninfo --summary
|
||||||
|
GG_BUILD_VULKAN=1 GGML_VK_DISABLE_COOPMAT2=1 bash ./ci/run.sh ~/results/whisper.cpp ~/mnt/whisper.cpp
|
||||||
|
|
||||||
|
gpu-vulkan-nvidia-cm2:
|
||||||
|
runs-on: [self-hosted, Linux, NVIDIA, COOPMAT2]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
run: |
|
||||||
|
vulkaninfo --summary
|
||||||
|
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/whisper.cpp ~/mnt/whisper.cpp
|
||||||
|
|
||||||
|
gpu-metal:
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
run: |
|
||||||
|
GG_BUILD_METAL=1 bash ./ci/run.sh ~/results/whisper.cpp ~/mnt/whisper.cpp
|
||||||
|
|
||||||
|
gpu-vulkan:
|
||||||
|
runs-on: [self-hosted, macOS, ARM64]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
id: ggml-ci
|
||||||
|
run: |
|
||||||
|
vulkaninfo --summary
|
||||||
|
GG_BUILD_VULKAN=1 bash ./ci/run.sh ~/results/whisper.cpp ~/mnt/whisper.cpp
|
||||||
|
|
||||||
|
npu-amd-windows:
|
||||||
|
runs-on: [self-hosted, Windows, X64, strix-halo, devlab-dispatch]
|
||||||
|
timeout-minutes: 60
|
||||||
|
continue-on-error: true # advisory while the runner pool is new; revisit later
|
||||||
|
|
||||||
|
env:
|
||||||
|
FLEXML_URL: https://github.com/lemonade-sdk/whisper.cpp-rocm/releases/download/deps/flexmlrt-1.7.0-win.zip
|
||||||
|
MODEL: base
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- uses: microsoft/setup-msbuild@v2
|
||||||
|
|
||||||
|
- name: Install CMake if not available
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
$installed = Get-Command cmake -ErrorAction SilentlyContinue
|
||||||
|
if (-not $installed) {
|
||||||
|
$ver = "3.28.1"
|
||||||
|
$url = "https://github.com/Kitware/CMake/releases/download/v$ver/cmake-$ver-windows-x86_64.msi"
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile cmake.msi
|
||||||
|
Start-Process msiexec.exe -ArgumentList "/i cmake.msi /quiet /norestart" -Wait
|
||||||
|
$p = "C:\Program Files\CMake\bin"
|
||||||
|
$env:PATH = "$p;$env:PATH"
|
||||||
|
echo $p >> $env:GITHUB_PATH
|
||||||
|
cmake --version
|
||||||
|
if ($LASTEXITCODE -ne 0) { Write-Error "CMake install failed"; exit 1 }
|
||||||
|
} else { cmake --version }
|
||||||
|
|
||||||
|
- name: Download FlexML runtime
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest -Uri "${{ env.FLEXML_URL }}" -OutFile flexmlrt.zip
|
||||||
|
if (-Not (Test-Path "flexmlrt.zip")) { Write-Error "flexmlrt.zip not downloaded"; exit 1 }
|
||||||
|
if ((Get-Item "flexmlrt.zip").Length -eq 0) { Write-Error "flexmlrt.zip is empty"; exit 1 }
|
||||||
|
tar xf flexmlrt.zip
|
||||||
|
if ($LASTEXITCODE -ne 0) { Write-Error "Extraction failed"; exit 1 }
|
||||||
|
if (-not (Test-Path "flexmlrt")) { Write-Error "No flexmlrt directory after extraction"; exit 1 }
|
||||||
|
|
||||||
|
- name: Setup FlexML, configure and build
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
cd flexmlrt
|
||||||
|
call setup.bat
|
||||||
|
if errorlevel 1 ( echo ERROR: FlexML setup.bat failed & exit /b 1 )
|
||||||
|
cd ..
|
||||||
|
cmake -B build -A x64 -DCMAKE_BUILD_TYPE=Release -DWHISPER_VITISAI=ON
|
||||||
|
if errorlevel 1 ( echo ERROR: CMake configure failed & exit /b 1 )
|
||||||
|
cmake --build build --config Release -j
|
||||||
|
if errorlevel 1 ( echo ERROR: Build failed & exit /b 1 )
|
||||||
|
|
||||||
|
- name: Copy FlexML DLLs to build output
|
||||||
|
shell: powershell
|
||||||
|
run: |
|
||||||
|
foreach ($d in "flexmlrt/bin", "flexmlrt/lib") {
|
||||||
|
if (Test-Path "$d/*.dll") { Copy-Item "$d/*.dll" "build/bin/Release/" -Force }
|
||||||
|
}
|
||||||
|
if (-not (Test-Path "build/bin/Release/flexmlrt.dll")) {
|
||||||
|
Write-Error "flexmlrt.dll not staged next to binaries"; exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
- name: Download ggml model
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call models\download-ggml-model.cmd %MODEL% models
|
||||||
|
if not exist models\ggml-%MODEL%.bin ( echo ERROR: model download failed & exit /b 1 )
|
||||||
|
|
||||||
|
- name: Download NPU encoder cache
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
.\models\download-vitisai-model.cmd %MODEL%
|
||||||
|
if not exist models\ggml-%MODEL%-encoder-vitisai.rai ( echo ERROR: VitisAI encoder cache download failed & exit /b 1 )
|
||||||
|
|
||||||
|
- name: Run NPU smoke test
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
build\bin\Release\whisper-cli.exe -m models\ggml-%MODEL%.bin -f samples\jfk.wav > vitisai.log 2>&1
|
||||||
|
type vitisai.log
|
||||||
|
findstr /I /C:"vitisai" vitisai.log || ( echo ERROR: no VitisAI activity - encoder likely fell back to CPU & exit /b 1 )
|
||||||
|
findstr /I /C:"ask not what your country" vitisai.log || ( echo ERROR: incorrect transcription & exit /b 1 )
|
||||||
|
|
||||||
|
- name: Upload smoke test log
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: vitisai-smoke-log-windows
|
||||||
|
path: vitisai.log
|
||||||
|
|
||||||
|
npu-amd-linux:
|
||||||
|
runs-on: [self-hosted, Linux, X64, strix-halo, devlab-dispatch]
|
||||||
|
timeout-minutes: 60
|
||||||
|
continue-on-error: true # advisory while the runner pool is new; revisit later
|
||||||
|
|
||||||
|
env:
|
||||||
|
FLEXML_LINUX_URL: https://github.com/lemonade-sdk/whisper.cpp-rocm/releases/download/deps/flexmlrt-1.8.0-linux.tar.gz
|
||||||
|
MODEL: base
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Verify NPU device
|
||||||
|
run: |
|
||||||
|
lsmod | grep -q amdxdna || { echo "ERROR: amdxdna driver not loaded"; exit 1; }
|
||||||
|
ls /dev/accel/accel* || { echo "ERROR: no NPU accel device node"; exit 1; }
|
||||||
|
|
||||||
|
- name: Download FlexML runtime (Linux)
|
||||||
|
run: |
|
||||||
|
curl -L --fail -o flexmlrt.tar.gz "$FLEXML_LINUX_URL"
|
||||||
|
tar xf flexmlrt.tar.gz
|
||||||
|
source flexmlrt/setup.sh
|
||||||
|
echo "FlexmlRT_DIR=$PWD/flexmlrt/share/cmake/FlexmlRT" >> $GITHUB_ENV
|
||||||
|
echo "LD_LIBRARY_PATH=$PWD/flexmlrt/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure and build
|
||||||
|
run: |
|
||||||
|
cmake -B build -DCMAKE_BUILD_TYPE=Release -DWHISPER_VITISAI=ON
|
||||||
|
cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
|
- name: Download ggml model
|
||||||
|
run: |
|
||||||
|
./models/download-ggml-model.sh $MODEL
|
||||||
|
|
||||||
|
- name: Download NPU encoder cache
|
||||||
|
run: |
|
||||||
|
sh ./models/download-vitisai-model.sh $MODEL
|
||||||
|
[ -f "models/ggml-$MODEL-encoder-vitisai.rai" ] || { echo "ERROR: VitisAI encoder cache download failed"; exit 1; }
|
||||||
|
|
||||||
|
- name: Run NPU smoke test
|
||||||
|
run: |
|
||||||
|
./build/bin/whisper-cli -m "models/ggml-$MODEL.bin" -f samples/jfk.wav 2>&1 | tee vitisai.log
|
||||||
|
grep -qi "vitisai" vitisai.log || { echo "ERROR: no VitisAI activity - CPU fallback?"; exit 1; }
|
||||||
|
grep -qi "ask not what your country" vitisai.log || { echo "ERROR: incorrect transcription"; exit 1; }
|
||||||
|
|
||||||
|
- name: Upload smoke test log
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: vitisai-smoke-log-linux
|
||||||
|
path: vitisai.log
|
||||||
150
.github/workflows/build-sycl.yml
vendored
Normal file
150
.github/workflows/build-sycl.yml
vendored
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
name: CI (sycl)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-sycl.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.cl']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-22-cmake-sycl:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
dwhisper_sycl: [ON]
|
||||||
|
dcmake_c_compiler: [icx]
|
||||||
|
dcmake_cxx_compiler: [icpx]
|
||||||
|
arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]
|
||||||
|
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: add oneAPI to apt
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd /tmp
|
||||||
|
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
|
||||||
|
|
||||||
|
- name: install oneAPI dpcpp compiler
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install intel-oneapi-compiler-dpcpp-cpp
|
||||||
|
|
||||||
|
- name: install oneAPI MKL library
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt install intel-oneapi-mkl-devel
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: sycl-${{ matrix.arch }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
id: cmake_build
|
||||||
|
env:
|
||||||
|
CCACHE_SLOPPINESS: time_macros
|
||||||
|
CCACHE_NODIRECT: 1
|
||||||
|
run: |
|
||||||
|
source /opt/intel/oneapi/setvars.sh
|
||||||
|
export CCACHE_COMPILERCHECK="string:$(icpx --version 2>&1 | head -1)"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DGGML_SYCL=ON -DGGML_NATIVE=OFF -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache ..
|
||||||
|
cmake --build . --config Release -j $(nproc)
|
||||||
|
|
||||||
|
ubuntu-22-cmake-sycl-fp16:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
dwhisper_sycl: [ON]
|
||||||
|
dcmake_c_compiler: [icx]
|
||||||
|
dcmake_cxx_compiler: [icpx]
|
||||||
|
arch: [linux/amd64, linux/arm64, linux/arm/v7, linux/ppc64le]
|
||||||
|
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: add oneAPI to apt
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd /tmp
|
||||||
|
wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB
|
||||||
|
sudo add-apt-repository "deb https://apt.repos.intel.com/oneapi all main"
|
||||||
|
|
||||||
|
- name: install oneAPI dpcpp compiler
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install intel-oneapi-compiler-dpcpp-cpp
|
||||||
|
|
||||||
|
- name: install oneAPI MKL library
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt install intel-oneapi-mkl-devel
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: sycl-fp16-${{ matrix.arch }}
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
id: cmake_build
|
||||||
|
env:
|
||||||
|
CCACHE_SLOPPINESS: time_macros
|
||||||
|
CCACHE_NODIRECT: 1
|
||||||
|
run: |
|
||||||
|
source /opt/intel/oneapi/setvars.sh
|
||||||
|
export CCACHE_COMPILERCHECK="string:$(icpx --version 2>&1 | head -1)"
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -DGGML_SYCL_F16=ON -DGGML_NATIVE=OFF -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache ..
|
||||||
|
cmake --build . --config Release -j $(nproc)
|
||||||
50
.github/workflows/build-vad.yml
vendored
Normal file
50
.github/workflows/build-vad.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
name: CI (vad)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-vad.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
vad:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: vad-ubuntu-latest
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cmake -B build -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DGGML_NATIVE=OFF
|
||||||
|
cmake --build build --config Release
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
ctest -R ^test-vad$ --test-dir build --output-on-failure -VV
|
||||||
65
.github/workflows/build-wasm.yml
vendored
Normal file
65
.github/workflows/build-wasm.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: CI (wasm)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-wasm.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
emscripten:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Setup emsdk
|
||||||
|
uses: emscripten-core/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
|
||||||
|
|
||||||
|
- name: Verify
|
||||||
|
run: emcc -v
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: wasm-ubuntu-22
|
||||||
|
evict-old-files: 1d
|
||||||
|
save: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
env:
|
||||||
|
CCACHE_SLOPPINESS: time_macros,include_file_mtime,include_file_ctime
|
||||||
|
CCACHE_COMPILERCHECK: content
|
||||||
|
run: |
|
||||||
|
emcmake cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build }} \
|
||||||
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
"-DCMAKE_C_FLAGS=-ffile-prefix-map=$EMSDK=/emsdk" \
|
||||||
|
"-DCMAKE_CXX_FLAGS=-ffile-prefix-map=$EMSDK=/emsdk"
|
||||||
|
cmake --build build -j $(nproc)
|
||||||
74
.github/workflows/build-windows.yml
vendored
Normal file
74
.github/workflows/build-windows.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: CI (windows)
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths: ['.github/workflows/build-windows.yml',
|
||||||
|
'**/CMakeLists.txt',
|
||||||
|
'**/Makefile',
|
||||||
|
'**/*.mk',
|
||||||
|
'**/*.cmake',
|
||||||
|
'**/*.in',
|
||||||
|
'**/*.h',
|
||||||
|
'**/*.hpp',
|
||||||
|
'**/*.c',
|
||||||
|
'**/*.cpp',
|
||||||
|
'**/*.cu',
|
||||||
|
'**/*.cuh',
|
||||||
|
'**/*.cl']
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
paths-ignore:
|
||||||
|
- 'bindings/ruby/**' # handled by bindings-ruby.yml
|
||||||
|
- 'bindings/go/**' # handled by bindings-go.yml
|
||||||
|
- 'examples/addon.node/**' # handled by examples.yml
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
windows-msys2:
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- { sys: UCRT64, env: ucrt-x86_64, compiler: gcc, build: Release }
|
||||||
|
- { sys: CLANG64, env: clang-x86_64, compiler: clang, build: Release }
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Setup ${{ matrix.sys }}
|
||||||
|
uses: msys2/setup-msys2@cafece8e6baf9247cf9b1bf95097b0b983cc558d # v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
msystem: ${{matrix.sys}}
|
||||||
|
install: >-
|
||||||
|
mingw-w64-${{matrix.env}}-${{matrix.compiler}}
|
||||||
|
mingw-w64-${{matrix.env}}-cmake
|
||||||
|
mingw-w64-${{matrix.env}}-SDL2
|
||||||
|
mingw-w64-${{matrix.env}}-openblas
|
||||||
|
|
||||||
|
- name: Build using CMake
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cmake -B build -DWHISPER_SDL2=ON
|
||||||
|
cmake --build build --config ${{ matrix.build }} -j $(nproc)
|
||||||
|
|
||||||
|
- name: Clean after building using CMake
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
rm -rf build
|
||||||
|
|
||||||
|
- name: Build using CMake w/ OpenBLAS
|
||||||
|
shell: msys2 {0}
|
||||||
|
run: |
|
||||||
|
cmake -B build -DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS
|
||||||
|
cmake --build build --config ${{ matrix.build }} -j $(nproc)
|
||||||
28
.github/workflows/close-issue.yml
vendored
Normal file
28
.github/workflows/close-issue.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
name: Mark inactive issues stale
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: "42 0 * * *"
|
||||||
|
|
||||||
|
# Fine-grant permission
|
||||||
|
# https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
mark-issues:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v10
|
||||||
|
with:
|
||||||
|
exempt-issue-labels: "refactor,help wanted,good first issue,research,bug,roadmap"
|
||||||
|
days-before-issue-stale: 30
|
||||||
|
days-before-issue-close: -1
|
||||||
|
stale-issue-label: "stale"
|
||||||
|
stale-issue-message: "This issue was marked as stale because it has been inactive for 30 days."
|
||||||
|
days-before-pr-stale: -1
|
||||||
|
days-before-pr-close: -1
|
||||||
|
operations-per-run: 10000
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
97
.github/workflows/deploy-examples-wasm.yml
vendored
Normal file
97
.github/workflows/deploy-examples-wasm.yml
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
name: Examples WASM
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: ["master"]
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: "pages"
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-wasm-github-pages:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
|
||||||
|
|
||||||
|
- name: Setup emsdk
|
||||||
|
uses: emscripten-core/setup-emsdk@6ab9eb1bda2574c4ddb79809fc9247783eaf9021 # v14
|
||||||
|
|
||||||
|
- name: Build WASM Examples
|
||||||
|
# Enable for real build later in whisper.cpp
|
||||||
|
run: |
|
||||||
|
mkdir -p build-em && cd build-em
|
||||||
|
emcmake cmake .. -DCMAKE_BUILD_TYPE=Release
|
||||||
|
make -j
|
||||||
|
|
||||||
|
- name: Create staging directory
|
||||||
|
run: mkdir -p staging
|
||||||
|
|
||||||
|
- name: Create .nojekyll file in staging directory
|
||||||
|
run: touch staging/.nojekyll
|
||||||
|
|
||||||
|
- name: Copy application files
|
||||||
|
run: |
|
||||||
|
build_dir=build-em/bin
|
||||||
|
|
||||||
|
ls ${build_dir}
|
||||||
|
|
||||||
|
# command.wasm
|
||||||
|
target_dir=staging/command.wasm
|
||||||
|
mkdir -p ${target_dir}
|
||||||
|
cp ${build_dir}/command.wasm/{index.html,command.js,helpers.js} ${target_dir}
|
||||||
|
cp ${build_dir}/libcommand.js ${target_dir}
|
||||||
|
|
||||||
|
# bench.wasm
|
||||||
|
target_dir=staging/bench.wasm
|
||||||
|
mkdir -p ${target_dir}
|
||||||
|
cp ${build_dir}/bench.wasm/{index.html,bench.js,helpers.js} ${target_dir}
|
||||||
|
cp ${build_dir}/libbench.js ${target_dir}
|
||||||
|
|
||||||
|
# stream.wasm
|
||||||
|
target_dir=staging/stream.wasm
|
||||||
|
mkdir -p ${target_dir}
|
||||||
|
cp ${build_dir}/stream.wasm/{index.html,stream.js,helpers.js} ${target_dir}
|
||||||
|
cp ${build_dir}/libstream.js ${target_dir}
|
||||||
|
|
||||||
|
# wchess.wasm
|
||||||
|
target_dir=staging/wchess.wasm
|
||||||
|
mkdir -p ${target_dir}
|
||||||
|
cp -r ${build_dir}/wchess.wasm/{index.html,css,img,js} ${target_dir}
|
||||||
|
cp ${build_dir}/wchess.wasm.js ${target_dir}
|
||||||
|
|
||||||
|
# whisper.wasm (this will be the main example page)
|
||||||
|
target_dir=staging
|
||||||
|
mkdir -p ${target_dir}
|
||||||
|
cp ${build_dir}/whisper.wasm/{index.html,main.js,helpers.js} ${target_dir}
|
||||||
|
cp ${build_dir}/libmain.js ${target_dir}
|
||||||
|
|
||||||
|
# Copy Cross-Origin Isolation service worker
|
||||||
|
cp -v examples/coi-serviceworker.js staging/
|
||||||
|
|
||||||
|
- name: List files in staging directory (for debugging)
|
||||||
|
run: |
|
||||||
|
echo "Files in staging directory:"
|
||||||
|
find staging -type f | sort
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4
|
||||||
|
with:
|
||||||
|
path: ./staging
|
||||||
|
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
|
||||||
73
.github/workflows/docker.yml
vendored
Normal file
73
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Publish Docker image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch: # allows manual triggering
|
||||||
|
schedule:
|
||||||
|
# Rebuild daily rather than on every push because it is expensive
|
||||||
|
- cron: '12 4 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
push_to_registry:
|
||||||
|
name: Push Docker image to Docker Hub
|
||||||
|
|
||||||
|
runs-on: ${{ matrix.config.runs_on }}
|
||||||
|
env:
|
||||||
|
COMMIT_SHA: ${{ github.sha }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- { tag: "main", dockerfile: ".devops/main.Dockerfile", platform: "linux/amd64", runs_on: "ubuntu-24.04" }
|
||||||
|
- { tag: "main-arm64", dockerfile: ".devops/main.Dockerfile", platform: "linux/arm64", runs_on: "ubuntu-24.04-arm" }
|
||||||
|
- { tag: "main-musa", dockerfile: ".devops/main-musa.Dockerfile", platform: "linux/amd64", runs_on: "ubuntu-24.04" }
|
||||||
|
- { tag: "main-intel", dockerfile: ".devops/main-intel.Dockerfile", platform: "linux/amd64", runs_on: "ubuntu-24.04" }
|
||||||
|
- { tag: "main-cuda", dockerfile: ".devops/main-cuda.Dockerfile", platform: "linux/amd64", runs_on: "ubuntu-24.04" }
|
||||||
|
- { tag: "main-vulkan", dockerfile: ".devops/main-vulkan.Dockerfile", platform: "linux/amd64", runs_on: "ubuntu-24.04" }
|
||||||
|
- { tag: "main-vulkan-arm64", dockerfile: ".devops/main-vulkan.Dockerfile", platform: "linux/arm64", runs_on: "ubuntu-24.04-arm" }
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out the repo
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
|
||||||
|
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Free up disk space
|
||||||
|
run: |
|
||||||
|
sudo apt-get remove -y '^dotnet-.*' '^llvm-.*' '^mysql-.*' '^postgresql-.*'
|
||||||
|
sudo apt-get autoremove -y
|
||||||
|
sudo apt-get autoclean
|
||||||
|
|
||||||
|
sudo rm -rf /usr/share/dotnet
|
||||||
|
sudo rm -rf /usr/local/lib/android
|
||||||
|
sudo rm -rf /opt/ghc
|
||||||
|
sudo rm -rf /opt/hostedtoolcache/CodeQL
|
||||||
|
|
||||||
|
docker system prune -af
|
||||||
|
|
||||||
|
df -h
|
||||||
|
|
||||||
|
- name: Generate tags
|
||||||
|
id: tags
|
||||||
|
run: |
|
||||||
|
TAGS="ghcr.io/${{ github.repository }}:${{ matrix.config.tag }}"
|
||||||
|
TAGS="$TAGS,ghcr.io/${{ github.repository }}:${{ matrix.config.tag }}-${{ env.COMMIT_SHA }}"
|
||||||
|
echo "tags=$TAGS" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Build and push Docker image (tagged)
|
||||||
|
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
push: true
|
||||||
|
platforms: ${{ matrix.config.platform }}
|
||||||
|
tags: ${{ steps.tags.outputs.tags }}
|
||||||
|
file: ${{ matrix.config.dockerfile }}
|
||||||
|
secrets: |
|
||||||
|
HF_TOKEN=${{ secrets.HF_TOKEN }}
|
||||||
53
.github/workflows/examples.yml
vendored
Normal file
53
.github/workflows/examples.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Examples Tests
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- examples/addon.node/**
|
||||||
|
- include/whisper.h
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- examples/addon.node/**
|
||||||
|
- include/whisper.h
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
addon_node-ubuntu-22:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [ 20.x, 22.x ]
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install build-essential git
|
||||||
|
sudo apt-get install cmake
|
||||||
|
sudo apt-get install libsdl2-dev
|
||||||
|
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: examples/addon.node/package-lock.json
|
||||||
|
|
||||||
|
- name: Install package.json dependencies
|
||||||
|
working-directory: ./examples/addon.node
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Compile addon.node
|
||||||
|
run: npx cmake-js compile -T addon.node -B Release
|
||||||
|
|
||||||
|
- name: Download test model
|
||||||
|
env:
|
||||||
|
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
||||||
|
run: |
|
||||||
|
bash ./models/download-ggml-model.sh base.en
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
cd examples/addon.node
|
||||||
|
npm run test
|
||||||
88
.github/workflows/make-release.yml
vendored
Normal file
88
.github/workflows/make-release.yml
vendored
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
name: Make Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
commit:
|
||||||
|
description: 'Commit SHA to release (empty = branch HEAD)'
|
||||||
|
required: false
|
||||||
|
default: ''
|
||||||
|
type: string
|
||||||
|
dry_run:
|
||||||
|
description: 'Dry run - validate without creating the tag'
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
make-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.commit != '' && inputs.commit || github.ref_name }}
|
||||||
|
fetch-depth: 0
|
||||||
|
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
||||||
|
|
||||||
|
- name: Run release checks
|
||||||
|
id: checks
|
||||||
|
run: bash scripts/make-release-checks.sh ${{ github.event.inputs.dry_run == 'true' && '--dry-run' || '' }}
|
||||||
|
env:
|
||||||
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
|
RELEASE_BRANCH: ${{ github.ref_name }}
|
||||||
|
|
||||||
|
- name: Create release tag
|
||||||
|
if: ${{ github.event.inputs.dry_run == 'false' }}
|
||||||
|
run: |
|
||||||
|
VERSION="${{ steps.checks.outputs.version }}"
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
git tag -a "${VERSION}" -m "Release ${VERSION}"
|
||||||
|
git push origin "${VERSION}"
|
||||||
|
echo "Created and pushed tag ${VERSION}"
|
||||||
|
|
||||||
|
- name: Generate release description
|
||||||
|
id: desc
|
||||||
|
run: bash scripts/make-release-desc.sh "${{ steps.checks.outputs.version }}"
|
||||||
|
env:
|
||||||
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
if: ${{ github.event.inputs.dry_run == 'false' }}
|
||||||
|
uses: ggml-org/action-create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ steps.checks.outputs.version }}
|
||||||
|
prerelease: false
|
||||||
|
# TODO: enrich the body of the release with more information
|
||||||
|
body: |
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
New version has been released.
|
||||||
|
|
||||||
|
${{ steps.desc.outputs.nightly }}
|
||||||
|
**More info:** [dist : releases and versioning of ggml-org projects](https://github.com/ggml-org/ggml/discussions/1579)
|
||||||
|
|
||||||
|
## ${{ steps.desc.outputs.changelog_title }}
|
||||||
|
|
||||||
|
${{ steps.desc.outputs.changelog }}
|
||||||
|
|
||||||
|
- name: Dry run summary
|
||||||
|
if: ${{ github.event.inputs.dry_run == 'true' }}
|
||||||
|
run: |
|
||||||
|
if [[ "${{ steps.checks.outputs.checks_passed }}" == "true" ]]; then
|
||||||
|
echo "Dry run complete - all checks passed."
|
||||||
|
echo "Would have created tag: ${{ steps.checks.outputs.version }}"
|
||||||
|
else
|
||||||
|
echo "::error::Dry run found release check failures. A release tag would not be created."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
941
.github/workflows/release.yml
vendored
Normal file
941
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,941 @@
|
|||||||
|
name: Release
|
||||||
|
|
||||||
|
# Builds dev releases (b* tags) when manually dispatched with create_release: true.
|
||||||
|
# Run this as a verification build before making a release (see make-release.yml).
|
||||||
|
# Pushing a v* tag does not trigger this workflow; releases are made via make-release.yml.
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
create_release:
|
||||||
|
description: 'Create new developer release'
|
||||||
|
required: true
|
||||||
|
type: boolean
|
||||||
|
pre_release_tag:
|
||||||
|
description: 'Pre-release tag name'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
|
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
|
||||||
|
WHISPER_BUILD_IS_DEV: OFF
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write # for creating release
|
||||||
|
id-token: write
|
||||||
|
attestations: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
determine-tag:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
tag_name: ${{ steps.tag.outputs.name }}
|
||||||
|
should_release: ${{ steps.tag.outputs.should_release }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout with full history
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Determine tag name
|
||||||
|
id: tag
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
BUILD_NUMBER=$(git rev-list --count HEAD)
|
||||||
|
SHORT_HASH=$(git rev-parse --short=7 HEAD)
|
||||||
|
CUSTOM_TAG="${{ github.event.inputs.pre_release_tag }}"
|
||||||
|
SHOULD_RELEASE="false"
|
||||||
|
|
||||||
|
echo "Raw values:"
|
||||||
|
echo "BUILD_NUMBER: $BUILD_NUMBER"
|
||||||
|
echo "SHORT_HASH: $SHORT_HASH"
|
||||||
|
echo "BRANCH_NAME: ${{ env.BRANCH_NAME }}"
|
||||||
|
echo "CUSTOM_TAG: $CUSTOM_TAG"
|
||||||
|
|
||||||
|
if [[ -n "$CUSTOM_TAG" ]]; then
|
||||||
|
echo "Using custom tag"
|
||||||
|
TAG_NAME="${CUSTOM_TAG}"
|
||||||
|
SHOULD_RELEASE="true"
|
||||||
|
elif [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
|
||||||
|
echo "Using master branch format"
|
||||||
|
TAG_NAME="b${BUILD_NUMBER}"
|
||||||
|
SHOULD_RELEASE="false"
|
||||||
|
else
|
||||||
|
echo "Using non-master branch format"
|
||||||
|
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
|
||||||
|
TAG_NAME="${SAFE_NAME}-b${BUILD_NUMBER}-${SHORT_HASH}"
|
||||||
|
SHOULD_RELEASE="false"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${{ github.event.inputs.create_release }}" == "true" ]]; then
|
||||||
|
echo "Manual release requested"
|
||||||
|
SHOULD_RELEASE="true"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Final tag name: $TAG_NAME"
|
||||||
|
echo "Should release: $SHOULD_RELEASE"
|
||||||
|
echo "name=$TAG_NAME" >> $GITHUB_OUTPUT
|
||||||
|
echo "should_release=$SHOULD_RELEASE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
ubuntu-cpu:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
needs: determine-tag
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- build: x64
|
||||||
|
os: ubuntu-22.04
|
||||||
|
- build: arm64
|
||||||
|
os: ubuntu-22.04-arm
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: release-${{ matrix.os }}-cpu
|
||||||
|
evict-old-files: 1d
|
||||||
|
|
||||||
|
- name: Dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y build-essential cmake
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cmake -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_INSTALL_RPATH='$ORIGIN' \
|
||||||
|
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||||
|
-DGGML_BACKEND_DL=ON \
|
||||||
|
-DGGML_NATIVE=OFF \
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }} \
|
||||||
|
${{ matrix.build == 'x64' && '-DGGML_CPU_ALL_VARIANTS=ON' || '-DGGML_CPU_ARM_ARCH=armv8-a' }}
|
||||||
|
cmake --build build --config Release -j $(nproc)
|
||||||
|
|
||||||
|
- name: Pack artifacts
|
||||||
|
run: |
|
||||||
|
cp LICENSE ./build/bin/
|
||||||
|
tar -czvf whisper-bin-ubuntu-${{ matrix.build }}.tar.gz \
|
||||||
|
--transform "s,^\.,whisper-bin-ubuntu-${{ matrix.build }}," \
|
||||||
|
-C ./build/bin .
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
path: whisper-bin-ubuntu-${{ matrix.build }}.tar.gz
|
||||||
|
name: whisper-bin-ubuntu-${{ matrix.build }}.tar.gz
|
||||||
|
|
||||||
|
windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
arch: [Win32, x64]
|
||||||
|
sdl2: [ON]
|
||||||
|
include:
|
||||||
|
- arch: Win32
|
||||||
|
s2arc: x86
|
||||||
|
jnaPath: win32-x86
|
||||||
|
- arch: x64
|
||||||
|
s2arc: x64
|
||||||
|
jnaPath: win32-x86-64
|
||||||
|
- sdl2: ON
|
||||||
|
s2ver: 2.28.5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
|
||||||
|
|
||||||
|
- name: Fetch SDL2 and set SDL2_DIR
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: |
|
||||||
|
C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip
|
||||||
|
7z x sdl2.zip
|
||||||
|
echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: >
|
||||||
|
cmake -S . -B ./build -A ${{ matrix.arch }}
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }}
|
||||||
|
-DBUILD_SHARED_LIBS=ON
|
||||||
|
-DWHISPER_SDL2=${{ matrix.sdl2 }}
|
||||||
|
-DGGML_NATIVE=OFF
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }}
|
||||||
|
${{ matrix.arch == 'x64' && '-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON' || '-DGGML_BMI2=OFF' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd ./build
|
||||||
|
msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }}
|
||||||
|
|
||||||
|
- name: Copy SDL2.dll
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Upload SDL2.dll
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: ${{ matrix.s2arc }}_SDL2.dll
|
||||||
|
path: build/bin/${{ matrix.build }}/SDL2.dll
|
||||||
|
|
||||||
|
- name: Upload whisper dll
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper_${{ matrix.arch }}.dll
|
||||||
|
path: build/bin/${{ matrix.build }}/whisper.dll
|
||||||
|
|
||||||
|
- name: Upload ggml dll
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: ggml_${{ matrix.arch }}.dll
|
||||||
|
path: build/bin/${{ matrix.build }}/ggml.dll
|
||||||
|
overwrite: true
|
||||||
|
|
||||||
|
- name: Upload ggml base dll
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: ggml_base_${{ matrix.arch }}.dll
|
||||||
|
path: build/bin/${{ matrix.build }}/ggml-base.dll
|
||||||
|
|
||||||
|
- name: Upload ggml cpu dll
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: ggml_cpu_${{ matrix.arch }}.dll
|
||||||
|
path: build/bin/${{ matrix.build }}/ggml-cpu.dll
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-bin-${{ matrix.arch }}.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ matrix.sdl2 == 'ON' && needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-bin-${{ matrix.arch }}.zip
|
||||||
|
path: whisper-bin-${{ matrix.arch }}.zip
|
||||||
|
|
||||||
|
windows-blas:
|
||||||
|
runs-on: windows-latest
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
arch: [Win32, x64]
|
||||||
|
blas: [ON]
|
||||||
|
sdl2: [ON]
|
||||||
|
blasver: [0.3.29]
|
||||||
|
include:
|
||||||
|
- arch: Win32
|
||||||
|
s2arc: x86
|
||||||
|
blasfile: x86
|
||||||
|
- arch: x64
|
||||||
|
s2arc: x64
|
||||||
|
blasfile: x64_64
|
||||||
|
- sdl2: ON
|
||||||
|
s2ver: 2.28.5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Export GitHub Actions cache environment variables
|
||||||
|
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');
|
||||||
|
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
|
||||||
|
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
|
||||||
|
|
||||||
|
- name: Install OpenBLAS and pkgconfiglite
|
||||||
|
if: matrix.blas == 'ON'
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest "https://github.com/OpenMathLib/OpenBLAS/releases/download/v${{matrix.blasver}}/OpenBLAS-${{matrix.blasver}}_${{matrix.blasfile}}.zip" -OutFile "OpenBLAS-${{matrix.blasver}}.zip"
|
||||||
|
Expand-Archive "OpenBLAS-${{matrix.blasver}}.zip" -DestinationPath "OpenBLAS-${{matrix.blasver}}"
|
||||||
|
choco install pkgconfiglite
|
||||||
|
|
||||||
|
- name: Fetch SDL2 and set SDL2_DIR
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: |
|
||||||
|
C:/msys64/usr/bin/wget.exe -qO sdl2.zip https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.s2ver }}/SDL2-devel-${{ matrix.s2ver }}-VC.zip
|
||||||
|
7z x sdl2.zip
|
||||||
|
echo "SDL2_DIR=$env:GITHUB_WORKSPACE/SDL2-${{ matrix.s2ver }}/cmake" >> $env:GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: >
|
||||||
|
cmake -S . -B ./build -A ${{ matrix.arch }}
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake"
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }}
|
||||||
|
-DGGML_BLAS=${{ matrix.blas }}
|
||||||
|
-DGGML_BLAS_VENDOR=OpenBLAS
|
||||||
|
-DBLAS_LIBRARIES="$env:GITHUB_WORKSPACE/OpenBLAS-${{matrix.blasver}}/lib/libopenblas.lib"
|
||||||
|
-DBLAS_INCLUDE_DIRS="$env:GITHUB_WORKSPACE/OpenBLAS-${{matrix.blasver}}/include"
|
||||||
|
-DWHISPER_SDL2=${{ matrix.sdl2 }}
|
||||||
|
-DGGML_NATIVE=OFF
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }}
|
||||||
|
${{ matrix.arch == 'x64' && '-DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON' || '-DGGML_BMI2=OFF' }}
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cd ./build
|
||||||
|
msbuild ALL_BUILD.vcxproj -t:build -p:configuration=${{ matrix.build }} -p:platform=${{ matrix.arch }}
|
||||||
|
|
||||||
|
- name: Copy openblas.dll
|
||||||
|
if: matrix.blas == 'ON'
|
||||||
|
run: copy "$env:GITHUB_WORKSPACE/OpenBLAS-${{matrix.blasver}}/bin/libopenblas.dll" build/bin/${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Copy SDL2.dll
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: copy "$env:SDL2_DIR/../lib/${{ matrix.s2arc }}/SDL2.dll" build/bin/${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-blas-bin-${{ matrix.arch }}.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ matrix.blas == 'ON' && matrix.sdl2 == 'ON' && needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-blas-bin-${{ matrix.arch }}.zip
|
||||||
|
path: whisper-blas-bin-${{ matrix.arch }}.zip
|
||||||
|
|
||||||
|
windows-cuda:
|
||||||
|
runs-on: windows-2022
|
||||||
|
needs: determine-tag
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
arch: [x64]
|
||||||
|
cublas: [ON]
|
||||||
|
sdl2: [ON]
|
||||||
|
cuda-toolkit: [12.4.0, 11.8.0]
|
||||||
|
include:
|
||||||
|
- arch: x64
|
||||||
|
sdl2: ON
|
||||||
|
sdl2_ver: 2.28.5
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Install Ninja
|
||||||
|
id: install_ninja
|
||||||
|
run: |
|
||||||
|
choco install ninja
|
||||||
|
|
||||||
|
- name: Install ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ${{ github.job }}-${{ matrix.cuda-toolkit }}-${{ matrix.build }}
|
||||||
|
evict-old-files: 5d
|
||||||
|
|
||||||
|
- name: Install Cuda Toolkit 11.8.0
|
||||||
|
if: ${{ matrix.cuda-toolkit == '11.8.0' }}
|
||||||
|
run: |
|
||||||
|
$CUDA_VERSION = ${{ matrix.cuda-toolkit }}
|
||||||
|
$CUDA_TOOLKIT_DIR = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$CUDA_VERSION"
|
||||||
|
$CUDA_DOWNLOAD = "https://developer.download.nvidia.com/compute/cuda/redist"
|
||||||
|
|
||||||
|
# Components versions
|
||||||
|
$CUDART_VER = "11.8.89"
|
||||||
|
$NVCC_VER = "11.8.89"
|
||||||
|
$NVRTC_VER = "11.8.89"
|
||||||
|
$CUBLAS_VER = "11.8.1.74"
|
||||||
|
$NVTX_VER = "11.8.86"
|
||||||
|
$VS_VER = "11.8.86"
|
||||||
|
$NVPROF_VER = "11.8.87"
|
||||||
|
$CCCL_VER = "11.8.89"
|
||||||
|
|
||||||
|
# Create the directory where the CUDA Toolkit will be installed
|
||||||
|
mkdir -p $CUDA_TOOLKIT_DIR
|
||||||
|
|
||||||
|
# Install unzip to extract the downloaded files
|
||||||
|
choco install unzip -y
|
||||||
|
|
||||||
|
# Download all the required components
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_cudart/windows-x86_64/cuda_cudart-windows-x86_64-${CUDART_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-${NVCC_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvrtc/windows-x86_64/cuda_nvrtc-windows-x86_64-${NVRTC_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/libcublas/windows-x86_64/libcublas-windows-x86_64-${CUBLAS_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvtx/windows-x86_64/cuda_nvtx-windows-x86_64-${NVTX_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/visual_studio_integration/windows-x86_64/visual_studio_integration-windows-x86_64-${VS_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvprof/windows-x86_64/cuda_nvprof-windows-x86_64-${NVPROF_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_cccl/windows-x86_64/cuda_cccl-windows-x86_64-${CCCL_VER}-archive.zip"
|
||||||
|
|
||||||
|
# Extract all the downloaded files to the CUDA Toolkit directory
|
||||||
|
unzip '*.zip' -d $CUDA_TOOLKIT_DIR
|
||||||
|
|
||||||
|
# Copy all the extracted files to the main CUDA Toolkit directory
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_cudart-windows-x86_64-${CUDART_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvcc-windows-x86_64-${NVCC_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvrtc-windows-x86_64-${NVRTC_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\libcublas-windows-x86_64-${CUBLAS_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvtx-windows-x86_64-${NVTX_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvprof-windows-x86_64-${NVPROF_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_cccl-windows-x86_64-${CCCL_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\visual_studio_integration-windows-x86_64-${VS_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
|
||||||
|
# Visual Studio integration
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\visual_studio_integration-windows-x86_64-${VS_VER}-archive\visual_studio_integration\MSBuildExtensions\*" "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\BuildCustomizations" /E /I /H /Y
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
echo "$CUDA_TOOLKIT_DIR\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
echo "$CUDA_TOOLKIT_DIR\libnvvp" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
echo "CUDA_PATH=$CUDA_TOOLKIT_DIR" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
echo "CUDA_PATH_V11_8=$CUDA_TOOLKIT_DIR" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
|
||||||
|
- name: Install Cuda Toolkit 12.4.0
|
||||||
|
if: ${{ matrix.cuda-toolkit == '12.4.0' }}
|
||||||
|
run: |
|
||||||
|
$CUDA_VERSION = ${{ matrix.cuda-toolkit }}
|
||||||
|
$CUDA_TOOLKIT_DIR = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$CUDA_VERSION"
|
||||||
|
$CUDA_DOWNLOAD = "https://developer.download.nvidia.com/compute/cuda/redist"
|
||||||
|
|
||||||
|
# Components versions
|
||||||
|
$CUDART_VER = "12.4.127"
|
||||||
|
$NVCC_VER = "12.4.131"
|
||||||
|
$NVRTC_VER = "12.4.127"
|
||||||
|
$CUBLAS_VER = "12.4.5.8"
|
||||||
|
$NVTX_VER = "12.4.127"
|
||||||
|
$PROFILER_VER = "12.4.127"
|
||||||
|
$VS_VER = "12.4.127"
|
||||||
|
$NVPROF_VER = "12.4.128"
|
||||||
|
$CCCL_VER = "12.4.127"
|
||||||
|
|
||||||
|
# Create the directory where the CUDA Toolkit will be installed
|
||||||
|
mkdir -p $CUDA_TOOLKIT_DIR
|
||||||
|
|
||||||
|
# Install unzip to extract the downloaded files
|
||||||
|
choco install unzip -y
|
||||||
|
|
||||||
|
# Download all the required components
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_cudart/windows-x86_64/cuda_cudart-windows-x86_64-${CUDART_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-${NVCC_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvrtc/windows-x86_64/cuda_nvrtc-windows-x86_64-${NVRTC_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/libcublas/windows-x86_64/libcublas-windows-x86_64-${CUBLAS_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvtx/windows-x86_64/cuda_nvtx-windows-x86_64-${NVTX_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_profiler_api/windows-x86_64/cuda_profiler_api-windows-x86_64-${PROFILER_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/visual_studio_integration/windows-x86_64/visual_studio_integration-windows-x86_64-${VS_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvprof/windows-x86_64/cuda_nvprof-windows-x86_64-${NVPROF_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_cccl/windows-x86_64/cuda_cccl-windows-x86_64-${CCCL_VER}-archive.zip"
|
||||||
|
|
||||||
|
# Extract all the downloaded files to the CUDA Toolkit directory
|
||||||
|
unzip -q '*.zip' -d $CUDA_TOOLKIT_DIR
|
||||||
|
|
||||||
|
# Copy all the extracted files to the main CUDA Toolkit directory
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_cudart-windows-x86_64-${CUDART_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvcc-windows-x86_64-${NVCC_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvrtc-windows-x86_64-${NVRTC_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\libcublas-windows-x86_64-${CUBLAS_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvtx-windows-x86_64-${NVTX_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvprof-windows-x86_64-${NVPROF_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_cccl-windows-x86_64-${CCCL_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_profiler_api-windows-x86_64-${PROFILER_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\visual_studio_integration-windows-x86_64-${VS_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
|
||||||
|
# Visual Studio integration
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\visual_studio_integration-windows-x86_64-${VS_VER}-archive\visual_studio_integration\MSBuildExtensions\*" "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\BuildCustomizations" /E /I /H /Y
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
echo "$CUDA_TOOLKIT_DIR\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
echo "$CUDA_TOOLKIT_DIR\libnvvp" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
echo "CUDA_PATH=$CUDA_TOOLKIT_DIR" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
echo "CUDA_PATH_V12_2=$CUDA_TOOLKIT_DIR" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # v2
|
||||||
|
|
||||||
|
- name: Install 7-Zip
|
||||||
|
run: choco install 7zip -y
|
||||||
|
|
||||||
|
- name: Fetch SDL2 and set SDL2_DIR
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: |
|
||||||
|
Invoke-WebRequest -Uri https://github.com/libsdl-org/SDL/releases/download/release-${{ matrix.sdl2_ver }}/SDL2-devel-${{ matrix.sdl2_ver }}-VC.zip -OutFile sdl2.zip
|
||||||
|
7z x sdl2.zip
|
||||||
|
echo "SDL2_DIR=${{ github.workspace }}\SDL2-${{ matrix.sdl2_ver }}\cmake" | Out-File -FilePath $env:GITHUB_ENV -Append
|
||||||
|
echo "${{ github.workspace }}\SDL2-${{ matrix.sdl2_ver }}\cmake" > SDL2_PATH.txt
|
||||||
|
|
||||||
|
- name: Install cmake
|
||||||
|
run: choco install cmake
|
||||||
|
|
||||||
|
- name: Build Project
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
|
||||||
|
cmake --version
|
||||||
|
where cmake
|
||||||
|
if "${{ matrix.cuda-toolkit }}" == "11.8.0" (
|
||||||
|
set CUDA_FLAGS=-allow-unsupported-compiler -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR
|
||||||
|
) else (
|
||||||
|
set CUDA_FLAGS=
|
||||||
|
)
|
||||||
|
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }} ^
|
||||||
|
-DGGML_CUDA=${{ matrix.cublas }} ^
|
||||||
|
-DWHISPER_SDL2=${{ matrix.sdl2 }} ^
|
||||||
|
-DSDL2_DIR="%SDL2_DIR%" ^
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^
|
||||||
|
-DCMAKE_CUDA_FLAGS="%CUDA_FLAGS%" ^
|
||||||
|
-DGGML_BACKEND_DL=ON ^
|
||||||
|
-DGGML_NATIVE=OFF ^
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }} ^
|
||||||
|
-DGGML_CPU_ALL_VARIANTS=ON
|
||||||
|
set /A NINJA_JOBS=%NUMBER_OF_PROCESSORS%-1
|
||||||
|
cmake --build build --config ${{ matrix.build }} -j %NUMBER_OF_PROCESSORS%
|
||||||
|
|
||||||
|
- name: Check ccache status after build
|
||||||
|
run: |
|
||||||
|
ccache --show-stats
|
||||||
|
|
||||||
|
- name: Copy CUDA DLLs
|
||||||
|
run: |
|
||||||
|
Get-ChildItem "$env:CUDA_PATH\bin\" -Filter "*.dll" |
|
||||||
|
Copy-Item -Destination "build/bin/${{ matrix.build }}"
|
||||||
|
|
||||||
|
- name: Copy SDL2.dll
|
||||||
|
if: matrix.sdl2 == 'ON'
|
||||||
|
run: copy "$env:SDL2_DIR/../lib/${{ matrix.arch }}/SDL2.dll" build/bin/${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-${{ matrix.arch }}.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-${{ matrix.arch }}.zip
|
||||||
|
path: whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-${{ matrix.arch }}.zip
|
||||||
|
|
||||||
|
windows-arm64-cpu:
|
||||||
|
runs-on: windows-2022
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Install Ninja
|
||||||
|
run: |
|
||||||
|
choco install ninja
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: release-windows-arm64-cpu
|
||||||
|
evict-old-files: 1d
|
||||||
|
|
||||||
|
- name: Configure and Build
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
|
||||||
|
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||||
|
-D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake ^
|
||||||
|
-DBUILD_SHARED_LIBS=ON ^
|
||||||
|
-DGGML_NATIVE=OFF ^
|
||||||
|
-DGGML_BACKEND_DL=ON ^
|
||||||
|
-DWHISPER_SDL2=OFF ^
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }}
|
||||||
|
cmake --build build --config ${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Copy OpenMP runtime DLL
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||||
|
$vsInstallPath = & $vswhere -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.ARM64 -property installationPath
|
||||||
|
if (-not $vsInstallPath) {
|
||||||
|
Write-Error "Could not find a Visual Studio install with the ARM64 MSVC toolset"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$redistVersion = Get-ChildItem "$vsInstallPath\VC\Redist\MSVC" -Directory |
|
||||||
|
Where-Object { $_.Name -match '^\d+\.\d+\.\d+$' } |
|
||||||
|
Sort-Object Name -Descending | Select-Object -First 1
|
||||||
|
$ompDll = "$vsInstallPath\VC\Redist\MSVC\$($redistVersion.Name)\debug_nonredist\arm64\Microsoft.VC143.OpenMP.LLVM\libomp140.aarch64.dll"
|
||||||
|
if (-not (Test-Path $ompDll)) {
|
||||||
|
Write-Error "libomp140.aarch64.dll not found at $ompDll"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Copy-Item $ompDll "build\bin\${{ matrix.build }}\" -Force
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-bin-win-cpu-arm64.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-bin-win-cpu-arm64.zip
|
||||||
|
path: whisper-bin-win-cpu-arm64.zip
|
||||||
|
|
||||||
|
windows-arm64-opencl-adreno:
|
||||||
|
runs-on: windows-2022
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Install Ninja
|
||||||
|
run: |
|
||||||
|
choco install ninja
|
||||||
|
|
||||||
|
- name: Install OpenCL Headers and Libs
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/KhronosGroup/OpenCL-Headers
|
||||||
|
cd OpenCL-Headers
|
||||||
|
cmake -B build `
|
||||||
|
-DBUILD_TESTING=OFF `
|
||||||
|
-DOPENCL_HEADERS_BUILD_TESTING=OFF `
|
||||||
|
-DOPENCL_HEADERS_BUILD_CXX_TESTS=OFF `
|
||||||
|
-DCMAKE_INSTALL_PREFIX="$env:RUNNER_TEMP/opencl-arm64-release"
|
||||||
|
cmake --build build --target install
|
||||||
|
cd ..
|
||||||
|
git clone https://github.com/KhronosGroup/OpenCL-ICD-Loader
|
||||||
|
cd OpenCL-ICD-Loader
|
||||||
|
cmake -B build-arm64-release `
|
||||||
|
-A arm64 `
|
||||||
|
-DCMAKE_PREFIX_PATH="$env:RUNNER_TEMP/opencl-arm64-release" `
|
||||||
|
-DCMAKE_INSTALL_PREFIX="$env:RUNNER_TEMP/opencl-arm64-release"
|
||||||
|
cmake --build build-arm64-release --target install --config release
|
||||||
|
|
||||||
|
- name: ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: release-windows-arm64-opencl-adreno
|
||||||
|
evict-old-files: 1d
|
||||||
|
|
||||||
|
- name: Configure and Build
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
|
||||||
|
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||||
|
-D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm.cmake ^
|
||||||
|
-DCMAKE_PREFIX_PATH="%RUNNER_TEMP%/opencl-arm64-release" ^
|
||||||
|
-DBUILD_SHARED_LIBS=ON ^
|
||||||
|
-DGGML_NATIVE=OFF ^
|
||||||
|
-DGGML_BACKEND_DL=ON ^
|
||||||
|
-DGGML_OPENCL=ON ^
|
||||||
|
-DGGML_OPENCL_USE_ADRENO_KERNELS=ON ^
|
||||||
|
-DWHISPER_SDL2=OFF ^
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }}
|
||||||
|
cmake --build build --config ${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Copy OpenMP runtime DLL
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||||
|
$vsInstallPath = & $vswhere -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.ARM64 -property installationPath
|
||||||
|
if (-not $vsInstallPath) {
|
||||||
|
Write-Error "Could not find a Visual Studio install with the ARM64 MSVC toolset"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$redistVersion = Get-ChildItem "$vsInstallPath\VC\Redist\MSVC" -Directory |
|
||||||
|
Where-Object { $_.Name -match '^\d+\.\d+\.\d+$' } |
|
||||||
|
Sort-Object Name -Descending | Select-Object -First 1
|
||||||
|
$ompDll = "$vsInstallPath\VC\Redist\MSVC\$($redistVersion.Name)\debug_nonredist\arm64\Microsoft.VC143.OpenMP.LLVM\libomp140.aarch64.dll"
|
||||||
|
if (-not (Test-Path $ompDll)) {
|
||||||
|
Write-Error "libomp140.aarch64.dll not found at $ompDll"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Copy-Item $ompDll "build\bin\${{ matrix.build }}\" -Force
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-bin-win-opencl-adreno-arm64.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-bin-win-opencl-adreno-arm64.zip
|
||||||
|
path: whisper-bin-win-opencl-adreno-arm64.zip
|
||||||
|
|
||||||
|
windows-arm64-cuda:
|
||||||
|
runs-on: windows-2022
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
cuda-toolkit: ['13.4']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Install Ninja
|
||||||
|
run: |
|
||||||
|
choco install ninja
|
||||||
|
|
||||||
|
- name: Install ccache
|
||||||
|
uses: ggml-org/ccache-action@v1.2.21
|
||||||
|
with:
|
||||||
|
key: ${{ github.job }}-${{ matrix.cuda-toolkit }}-${{ matrix.build }}
|
||||||
|
evict-old-files: 5d
|
||||||
|
|
||||||
|
# nvcc cross-compiles for ARM64 from this x64 runner using the ARM64-targeting
|
||||||
|
# host cl.exe; the CUDA runtime/cublas libs still need their own ARM64 archives
|
||||||
|
# since the standard x64 CUDA packages don't ship ARM64 binaries.
|
||||||
|
- name: Install Cuda Toolkit 13.4 (ARM64 target)
|
||||||
|
run: |
|
||||||
|
$CUDA_TOOLKIT_DIR = "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.4"
|
||||||
|
$CUDA_DOWNLOAD = "https://developer.download.nvidia.com/compute/cuda/redist"
|
||||||
|
|
||||||
|
# Components versions
|
||||||
|
$CCCL_VER = "13.3.4.2.1"
|
||||||
|
$CRT_VER = "13.4.59"
|
||||||
|
$NVCC_VER = "13.4.59"
|
||||||
|
$NVVM_VER = "13.4.59"
|
||||||
|
$CUDART_VER = "13.4.49"
|
||||||
|
$CUBLAS_VER = "13.7.0.27"
|
||||||
|
|
||||||
|
mkdir -p $CUDA_TOOLKIT_DIR
|
||||||
|
choco install unzip -y
|
||||||
|
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cccl/windows-x86_64/cccl-windows-x86_64-${CCCL_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_crt/windows-x86_64/cuda_crt-windows-x86_64-${CRT_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_nvcc/windows-x86_64/cuda_nvcc-windows-x86_64-${NVCC_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/libnvvm/windows-x86_64/libnvvm-windows-x86_64-${NVVM_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/cuda_cudart/windows-arm64/cuda_cudart-windows-arm64-${CUDART_VER}-archive.zip"
|
||||||
|
curl -O "$CUDA_DOWNLOAD/libcublas/windows-arm64/libcublas-windows-arm64-${CUBLAS_VER}-archive.zip"
|
||||||
|
|
||||||
|
unzip '*.zip' -d $CUDA_TOOLKIT_DIR
|
||||||
|
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cccl-windows-x86_64-${CCCL_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_crt-windows-x86_64-${CRT_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_nvcc-windows-x86_64-${NVCC_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\libnvvm-windows-x86_64-${NVVM_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\cuda_cudart-windows-arm64-${CUDART_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
xcopy "$CUDA_TOOLKIT_DIR\libcublas-windows-arm64-${CUBLAS_VER}-archive\*" "$CUDA_TOOLKIT_DIR" /E /I /H /Y
|
||||||
|
|
||||||
|
echo "$CUDA_TOOLKIT_DIR\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
echo "CUDA_PATH=$CUDA_TOOLKIT_DIR" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
||||||
|
|
||||||
|
- name: Configure and Build
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" amd64_arm64
|
||||||
|
cmake -S . -B build -G "Ninja Multi-Config" ^
|
||||||
|
-D CMAKE_TOOLCHAIN_FILE=cmake/arm64-windows-llvm-cuda.cmake ^
|
||||||
|
-DCMAKE_BUILD_TYPE=${{ matrix.build }} ^
|
||||||
|
-DGGML_CUDA=ON ^
|
||||||
|
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 ^
|
||||||
|
-DGGML_BACKEND_DL=ON ^
|
||||||
|
-DGGML_NATIVE=OFF ^
|
||||||
|
-DWHISPER_SDL2=OFF ^
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }}
|
||||||
|
cmake --build build --config ${{ matrix.build }}
|
||||||
|
|
||||||
|
- name: Copy CUDA runtime DLLs
|
||||||
|
run: |
|
||||||
|
Get-ChildItem "$env:CUDA_PATH\bin\arm64" -Filter "cudart64_*.dll" | Copy-Item -Destination "build/bin/${{ matrix.build }}"
|
||||||
|
Get-ChildItem "$env:CUDA_PATH\bin\arm64" -Filter "cublas64_*.dll" | Copy-Item -Destination "build/bin/${{ matrix.build }}"
|
||||||
|
Get-ChildItem "$env:CUDA_PATH\bin\arm64" -Filter "cublasLt64_*.dll" | Copy-Item -Destination "build/bin/${{ matrix.build }}"
|
||||||
|
|
||||||
|
- name: Copy OpenMP runtime DLL
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||||
|
$vsInstallPath = & $vswhere -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.ARM64 -property installationPath
|
||||||
|
if (-not $vsInstallPath) {
|
||||||
|
Write-Error "Could not find a Visual Studio install with the ARM64 MSVC toolset"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$redistVersion = Get-ChildItem "$vsInstallPath\VC\Redist\MSVC" -Directory |
|
||||||
|
Where-Object { $_.Name -match '^\d+\.\d+\.\d+$' } |
|
||||||
|
Sort-Object Name -Descending | Select-Object -First 1
|
||||||
|
$ompDll = "$vsInstallPath\VC\Redist\MSVC\$($redistVersion.Name)\debug_nonredist\arm64\Microsoft.VC143.OpenMP.LLVM\libomp140.aarch64.dll"
|
||||||
|
if (-not (Test-Path $ompDll)) {
|
||||||
|
Write-Error "libomp140.aarch64.dll not found at $ompDll"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
Copy-Item $ompDll "build\bin\${{ matrix.build }}\" -Force
|
||||||
|
|
||||||
|
- name: Pack bin artifacts
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Compress-Archive -Path "build/bin/${{ matrix.build }}" -DestinationPath "whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-arm64.zip"
|
||||||
|
|
||||||
|
- name: Upload binaries
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
name: whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-arm64.zip
|
||||||
|
path: whisper-bin-win-cuda-${{ matrix.cuda-toolkit }}-arm64.zip
|
||||||
|
|
||||||
|
ios-xcode-build:
|
||||||
|
runs-on: macos-latest
|
||||||
|
needs: determine-tag
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
build: [Release]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
run: |
|
||||||
|
cp models/for-tests-ggml-base.en.bin models/ggml-base.en.bin
|
||||||
|
mkdir models/ggml-base.en-encoder.mlmodelc
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
id: cmake_build
|
||||||
|
run: |
|
||||||
|
sysctl -a
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
cmake -G Xcode .. \
|
||||||
|
-DGGML_METAL_USE_BF16=ON \
|
||||||
|
-DGGML_METAL_EMBED_LIBRARY=ON \
|
||||||
|
-DWHISPER_BUILD_IS_DEV=${{ env.WHISPER_BUILD_IS_DEV }} \
|
||||||
|
-DWHISPER_BUILD_EXAMPLES=OFF \
|
||||||
|
-DWHISPER_BUILD_TESTS=OFF \
|
||||||
|
-DWHISPER_BUILD_SERVER=OFF \
|
||||||
|
-DCMAKE_SYSTEM_NAME=iOS \
|
||||||
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=14.0 \
|
||||||
|
-DCMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM=ggml
|
||||||
|
cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) -- CODE_SIGNING_ALLOWED=NO
|
||||||
|
|
||||||
|
- name: xcodebuild for swift package
|
||||||
|
id: xcodebuild
|
||||||
|
run: |
|
||||||
|
./build-xcframework.sh
|
||||||
|
|
||||||
|
- name: Build objc example
|
||||||
|
run: xcodebuild -project examples/whisper.objc/whisper.objc.xcodeproj -scheme whisper.objc -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO FRAMEWORK_FOLDER_PATH=./build-ios build
|
||||||
|
|
||||||
|
- name: Build swiftui example
|
||||||
|
run: xcodebuild -project examples/whisper.swiftui/whisper.swiftui.xcodeproj -scheme WhisperCppDemo -configuration ${{ matrix.build }} -sdk iphoneos CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= -destination 'generic/platform=iOS' FRAMEWORK_FOLDER_PATH=./build-ios build
|
||||||
|
|
||||||
|
- name: Pack artifacts
|
||||||
|
id: pack_artifacts
|
||||||
|
run: |
|
||||||
|
zip --symlinks -r whisper-${{ needs.determine-tag.outputs.tag_name }}-xcframework.zip build-apple/whisper.xcframework
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
if: ${{ needs.determine-tag.outputs.should_release == 'true' }}
|
||||||
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
|
||||||
|
with:
|
||||||
|
path: whisper-${{ needs.determine-tag.outputs.tag_name }}-xcframework.zip
|
||||||
|
name: whisper-${{ needs.determine-tag.outputs.tag_name }}-xcframework.zip
|
||||||
|
|
||||||
|
release:
|
||||||
|
if: ${{ github.event.inputs.create_release == 'true' || github.event.inputs.pre_release_tag != '' }}
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- determine-tag
|
||||||
|
- ubuntu-cpu
|
||||||
|
- ios-xcode-build
|
||||||
|
- windows
|
||||||
|
- windows-blas
|
||||||
|
- windows-cuda
|
||||||
|
- windows-arm64-cpu
|
||||||
|
- windows-arm64-opencl-adreno
|
||||||
|
- windows-arm64-cuda
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Clone
|
||||||
|
id: checkout
|
||||||
|
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ssh-key: ${{ secrets.DEPLOY_KEY_RELEASE }}
|
||||||
|
|
||||||
|
# Downloads all the artifacts from the previous jobs
|
||||||
|
- name: Download artifacts
|
||||||
|
id: download-artifact
|
||||||
|
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
||||||
|
with:
|
||||||
|
path: ./artifact
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: Move artifacts
|
||||||
|
id: move_artifacts
|
||||||
|
run: |
|
||||||
|
mkdir -p ./release
|
||||||
|
mv -v ./artifact/*.zip ./release 2>/dev/null || true
|
||||||
|
mv -v ./artifact/*.tar.gz ./release 2>/dev/null || true
|
||||||
|
|
||||||
|
- name: Attest release artifacts
|
||||||
|
uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4
|
||||||
|
with:
|
||||||
|
subject-path: 'release/*'
|
||||||
|
|
||||||
|
- name: Create and push git tag
|
||||||
|
run: |
|
||||||
|
TAG="${{ needs.determine-tag.outputs.tag_name }}"
|
||||||
|
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then
|
||||||
|
echo "Tag ${TAG} already exists, skipping creation"
|
||||||
|
else
|
||||||
|
git tag "${TAG}"
|
||||||
|
git push origin "${TAG}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
id: create_release
|
||||||
|
uses: ggml-org/action-create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ needs.determine-tag.outputs.tag_name }}
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
|
- name: Upload release
|
||||||
|
id: upload_release
|
||||||
|
uses: actions/github-script@ffc2c79a5b2490bd33e0a41c1de74b877714d736 # v3
|
||||||
|
with:
|
||||||
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
script: |
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const release_id = '${{ steps.create_release.outputs.id }}';
|
||||||
|
for (let file of await fs.readdirSync('./release')) {
|
||||||
|
if (path.extname(file) === '.zip' || file.endsWith('.tar.gz')) {
|
||||||
|
console.log('uploadReleaseAsset', file);
|
||||||
|
await github.repos.uploadReleaseAsset({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
release_id: release_id,
|
||||||
|
name: file,
|
||||||
|
data: await fs.readFileSync(`./release/${file}`)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
70
.gitignore
vendored
Normal file
70
.gitignore
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.d
|
||||||
|
.cache/
|
||||||
|
.coreml/
|
||||||
|
.test/
|
||||||
|
.venv/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
.DS_Store
|
||||||
|
.vimspector.json
|
||||||
|
/CMakeSettings.json
|
||||||
|
/CMakeUserPresets.json
|
||||||
|
/talk-llama.dSYM/
|
||||||
|
|
||||||
|
build/
|
||||||
|
build-*/
|
||||||
|
build_*/
|
||||||
|
tmp/
|
||||||
|
|
||||||
|
# SPM
|
||||||
|
.build/
|
||||||
|
.swiftpm
|
||||||
|
*.metallib
|
||||||
|
|
||||||
|
ggml-metal-embed.metal
|
||||||
|
ggml-metal-embed.metal.tmp
|
||||||
|
|
||||||
|
/main
|
||||||
|
/stream
|
||||||
|
/command
|
||||||
|
/talk
|
||||||
|
/talk-llama
|
||||||
|
/bench
|
||||||
|
/quantize
|
||||||
|
/server
|
||||||
|
/lsp
|
||||||
|
|
||||||
|
arm_neon.h
|
||||||
|
sync.sh
|
||||||
|
libwhisper.a
|
||||||
|
libwhisper.so
|
||||||
|
compile_commands.json
|
||||||
|
|
||||||
|
examples/arm_neon.h
|
||||||
|
examples/whisper.objc/whisper.objc.xcodeproj/xcshareddata
|
||||||
|
examples/whisper.objc/whisper.objc.xcodeproj/xcuserdata/
|
||||||
|
examples/whisper.objc/whisper.objc.xcodeproj/project.xcworkspace/xcuserdata
|
||||||
|
|
||||||
|
extra/bench-gg.txt
|
||||||
|
|
||||||
|
models/*.mlmodel
|
||||||
|
models/*.mlmodelc
|
||||||
|
models/*.mlpackage
|
||||||
|
models/*-encoder-openvino.xml
|
||||||
|
models/*-encoder-openvino-cache/
|
||||||
|
bindings/java/.gradle/
|
||||||
|
bindings/java/.idea/
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
benchmark_results.csv
|
||||||
|
cmake-build-debug/
|
||||||
|
.cxx/
|
||||||
|
.gradle/
|
||||||
|
local.properties
|
||||||
|
.log
|
||||||
|
.exe
|
||||||
|
|
||||||
|
# AGENTS
|
||||||
|
.pi/SYSTEM.md
|
||||||
30
.pi/gg/SYSTEM.md
Normal file
30
.pi/gg/SYSTEM.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
You are a coding agent. Here are some very important rules that you must follow:
|
||||||
|
|
||||||
|
General:
|
||||||
|
- Be very precise and concise when writing code, comments, explanations, etc.
|
||||||
|
- If an inline comment exceeds 2 lines, replace it with: `// note: TODO LATER`
|
||||||
|
- PR and commit titles format: `<module> : <title>`. Lookup recents for examples
|
||||||
|
- Don't try to build or run the code unless you are explicitly asked to do so
|
||||||
|
- Use the `gh` CLI tool when querying PRs, issues, or other GitHub resources
|
||||||
|
|
||||||
|
Coding:
|
||||||
|
- When in doubt, always refer to the CONTRIBUTING.md file of the project
|
||||||
|
- In `test-backend-ops.cpp`, do not mention specific backends (e.g. Metal, CUDA) in comments
|
||||||
|
- When referencing issues or PRs in comments, use the format:
|
||||||
|
- C/C++ code: `// ref: <url>`
|
||||||
|
- Other (CMake, etc.): `# ref: <url>`
|
||||||
|
|
||||||
|
Pull requests (PRs):
|
||||||
|
- New branch names are prefixed with "gg/"
|
||||||
|
- Before opening a pull request, ask the user to confirm the description
|
||||||
|
- Don't explicitly wrap lines in the PR description (each paragraph and bullet is a single line)
|
||||||
|
- When creating a pull request, look for the repository's PR template and follow it
|
||||||
|
- For the AI usage disclosure section, write "YES. pi:llama.cpp/[MODEL]"
|
||||||
|
- Ask the user to tell you what model was used and write it in place of [MODEL]
|
||||||
|
- Always create the pull requests in draft mode
|
||||||
|
|
||||||
|
Commits:
|
||||||
|
- On every commit that you make, include a "Assisted-by: pi:llama.cpp/[MODEL]" tag
|
||||||
|
- Do not explicitly set the git author in commits - rely on the default git config
|
||||||
|
- Always use `--no-gpg-sign` when committing
|
||||||
|
- Never `git push` without explicit confirmation from the user
|
||||||
102
AGENTS.md
Normal file
102
AGENTS.md
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
# Instructions for whisper.cpp
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
|
||||||
|
>
|
||||||
|
> Read more: [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||||
|
|
||||||
|
AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for corrections or to expand on verbose modifications that the contributor has already conceptualized (see examples below).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Guidelines for Contributors Using AI
|
||||||
|
|
||||||
|
whisper.cpp is built by humans, for humans. Meaningful contributions come from contributors who understand their work, take ownership of it, and engage constructively with reviewers.
|
||||||
|
|
||||||
|
Maintainers receive numerous pull requests weekly, many of which are AI-generated submissions where the author cannot adequately explain the code, debug issues, or participate in substantive design discussions. Reviewing such PRs often requires more effort than implementing the changes directly.
|
||||||
|
|
||||||
|
**A pull request represents a long-term commitment.** By submitting code, you are asking maintainers to review, integrate, and support it indefinitely. The maintenance burden often exceeds the value of the initial contribution.
|
||||||
|
|
||||||
|
Most maintainers already have access to AI tools. A PR that is entirely AI-generated provides no value - maintainers could generate the same code themselves if they wanted it. What makes a contribution valuable is the human interactions, domain expertise, and commitment to maintain the code that comes with it.
|
||||||
|
|
||||||
|
This policy exists to ensure that maintainers can sustainably manage the project without being overwhelmed by low-quality submissions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Guidelines for Contributors
|
||||||
|
|
||||||
|
Contributors are expected to:
|
||||||
|
|
||||||
|
1. **Demonstrate full understanding of their code.** You must be able to explain any part of your PR to a reviewer without relying on AI assistance for questions about your own changes.
|
||||||
|
|
||||||
|
2. **Take responsibility for maintenance.** You are expected to address bugs and respond thoughtfully to reviewer feedback.
|
||||||
|
|
||||||
|
3. **Communicate clearly and concisely.** Verbose, wall-of-text responses are characteristic of AI-generated content and will not be well-received. Direct, human communication is expected.
|
||||||
|
|
||||||
|
4. **Respect maintainers' time.** Search for existing issues and discussions before submitting. Ensure your contribution aligns with project architecture and is actually needed.
|
||||||
|
|
||||||
|
Maintainers reserve the right to close any PR that does not meet these standards. This applies to all contributions to the main whisper.cpp repository. **Private forks are exempt.**
|
||||||
|
|
||||||
|
### Permitted AI Usage
|
||||||
|
|
||||||
|
AI tools may be used responsibly for:
|
||||||
|
|
||||||
|
- **Learning and exploration**: Understanding codebase structure, techniques, and documentation
|
||||||
|
- **Code review assistance**: Obtaining suggestions on human-written code
|
||||||
|
- **Mechanical tasks**: Formatting, generating repetitive patterns from established designs, completing code based on existing patterns
|
||||||
|
- **Documentation drafts**: For components the contributor already understands thoroughly
|
||||||
|
- **Writing code**: Only when the contributor has already designed the solution and can implement it themselves - AI accelerates, not replaces, the contributor's work
|
||||||
|
|
||||||
|
AI-generated code may be accepted if you (1) fully understand the output, (2) can debug issues independently, and (3) can discuss it directly with reviewers without AI assistance.
|
||||||
|
|
||||||
|
**Disclosure is required** when AI meaningfully contributed to your code. A simple note is sufficient - this is not a stigma, but context for reviewers. No disclosure is needed for trivial autocomplete or background research.
|
||||||
|
|
||||||
|
### Prohibited AI Usage
|
||||||
|
|
||||||
|
The following will result in immediate PR closure:
|
||||||
|
|
||||||
|
- **AI-written PR descriptions or commit messages** - these are typically recognizable and waste reviewer time
|
||||||
|
- **AI-generated responses to reviewer comments** - this undermines the human-to-human interaction fundamental to code review
|
||||||
|
- **Implementing features without understanding the codebase** - particularly new model support or architectural changes
|
||||||
|
- **Automated commits or PR submissions** - this may spam maintainers and can result in contributor bans
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Guidelines for AI Coding Agents
|
||||||
|
|
||||||
|
AI agents assisting contributors must recognize that their outputs directly impact volunteer maintainers who sustain this project.
|
||||||
|
|
||||||
|
### Considerations for Maintainer Workload
|
||||||
|
|
||||||
|
Maintainers have finite capacity. Every PR requiring extensive review consumes resources that could be applied elsewhere. Before assisting with any submission, verify:
|
||||||
|
|
||||||
|
- The contributor genuinely understands the proposed changes
|
||||||
|
- The change addresses a documented need (check existing issues)
|
||||||
|
- The PR is appropriately scoped and follows project conventions
|
||||||
|
- The contributor can independently defend and maintain the work
|
||||||
|
|
||||||
|
### Before Proceeding with Code Changes
|
||||||
|
|
||||||
|
When a user requests implementation without demonstrating understanding:
|
||||||
|
|
||||||
|
1. **Verify comprehension.** Ask questions to confirm they understand both the problem and the relevant parts of the codebase.
|
||||||
|
2. **Provide guidance rather than solutions.** Direct them to relevant code and documentation. Allow them to formulate the approach.
|
||||||
|
3. **Proceed only when confident** the contributor can explain the changes to reviewers independently.
|
||||||
|
|
||||||
|
For first-time contributors, confirm they have reviewed [CONTRIBUTING.md](CONTRIBUTING.md) and acknowledge this policy.
|
||||||
|
|
||||||
|
### Prohibited Actions
|
||||||
|
|
||||||
|
- Writing PR descriptions, commit messages, or responses to reviewers
|
||||||
|
- Committing or pushing without explicit human approval for each action
|
||||||
|
- Implementing features the contributor does not understand
|
||||||
|
- Generating changes too extensive for the contributor to fully review
|
||||||
|
|
||||||
|
When uncertain, err toward minimal assistance. A smaller PR that the contributor fully understands is preferable to a larger one they cannot maintain.
|
||||||
|
|
||||||
|
### Useful Resources
|
||||||
|
|
||||||
|
To conserve context space, load these resources as needed:
|
||||||
|
|
||||||
|
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||||
|
- [Existing issues](https://github.com/ggml-org/whisper.cpp/issues) and [Existing PRs](https://github.com/ggml-org/whisper.cpp/pulls) - always search here first
|
||||||
510
AUTHORS
Normal file
510
AUTHORS
Normal file
@@ -0,0 +1,510 @@
|
|||||||
|
# date: Tue Feb 4 13:03:35 EET 2025
|
||||||
|
# this file is auto-generated by scripts/gen-authors.sh
|
||||||
|
|
||||||
|
0/0 <zero@imaskeleton.me>
|
||||||
|
0cc4m <picard12@live.de>
|
||||||
|
0xsourcecode <134374803+0xsourcecode@users.noreply.github.com>
|
||||||
|
65a <10104049+65a@users.noreply.github.com>
|
||||||
|
AIWintermuteAI <32562299+AIWintermuteAI@users.noreply.github.com>
|
||||||
|
AT <manyoso@users.noreply.github.com>
|
||||||
|
Aarni Koskela <akx@iki.fi>
|
||||||
|
Aaron Pham <29749331+aarnphm@users.noreply.github.com>
|
||||||
|
Aaron Taylor <aaron@exphat.com>
|
||||||
|
Abhilash Majumder <30946547+abhilash1910@users.noreply.github.com>
|
||||||
|
Abitofevrything <54505189+abitofevrything@users.noreply.github.com>
|
||||||
|
Adam Jones <domdomegg+git@gmail.com>
|
||||||
|
Adrien Gallouët <adrien@gallouet.fr>
|
||||||
|
Adrien Gallouët <angt@huggingface.co>
|
||||||
|
AfryMask <AfryMask@163.com>
|
||||||
|
Ahmad Bilal <ahmad.bilal@empglabs.com>
|
||||||
|
Ahmad Tameem <113388789+Tameem-10xE@users.noreply.github.com>
|
||||||
|
AidanBeltonS <87009434+AidanBeltonS@users.noreply.github.com>
|
||||||
|
AidanBeltonS <aidan.belton@codeplay.com>
|
||||||
|
Akarshan Biswas <akarshan.biswas@gmail.com>
|
||||||
|
Akarshan Biswas <akarshanbiswas@fedoraproject.org>
|
||||||
|
Akash Mahajan <akash7190@gmail.com>
|
||||||
|
Akash Mahajan <akashmjn@stanford.edu>
|
||||||
|
Al Hoang <3811822-hoanga@users.noreply.gitlab.com>
|
||||||
|
Alan <unknown>
|
||||||
|
Albert Jin <albert.jin@gmail.com>
|
||||||
|
Alberto Cabrera Pérez <alberto.cabrera@codeplay.com>
|
||||||
|
Alberto Cabrera Pérez <alberto.cabrera@intel.com>
|
||||||
|
Aleksander Andrzejewski <18704749+aleksanderandrzejewski@users.noreply.github.com>
|
||||||
|
Alex Azarov <alex@azarov.by>
|
||||||
|
Alex Bacart <13940752+alex-bacart@users.noreply.github.com>
|
||||||
|
Alex Evgrashin <aevgrashin@yandex.ru>
|
||||||
|
Alex O'Connell <35843486+acon96@users.noreply.github.com>
|
||||||
|
Alexandr Graschenkov <alexandr.graschenkov91@gmail.com>
|
||||||
|
Alexandru Mariuti <alex@mariuti.com>
|
||||||
|
Alexey Kharlamov <alexey@kharlamov.biz>
|
||||||
|
Alfredo Montesinos <alfredo.montesinos@g.austincc.edu>
|
||||||
|
Ali Alameh <ali.alameh@isae.edu.lb>
|
||||||
|
Alter <0x7c48@gmail.com>
|
||||||
|
Ananta Bastola <anantarajbastola@gmail.com>
|
||||||
|
Andreas Kieslinger <47689530+aendk@users.noreply.github.com>
|
||||||
|
Andreas Lubbe <git@lubbe.org>
|
||||||
|
Andreu Huguet <andreuhuguet@gmail.com>
|
||||||
|
Andrew Huynh <a5thuynh@gmail.com>
|
||||||
|
Andrew Minh Nguyen <40281306+amqdn@users.noreply.github.com>
|
||||||
|
Andrew S <andrews54757@gmail.com>
|
||||||
|
Andy Maloney <asmaloney@gmail.com>
|
||||||
|
Anton Kostin <masguit42@users.noreply.github.com>
|
||||||
|
Artyom Mezin <psycho.fading@gmail.com>
|
||||||
|
Asad Memon <asad.lionpk@gmail.com>
|
||||||
|
Ashraful Islam <ashraful.meche@gmail.com>
|
||||||
|
AsukaMinato <asukaminato@nyan.eu.org>
|
||||||
|
AustinMroz <austinmroz@utexas.edu>
|
||||||
|
Avik Sengupta <avik@sengupta.net>
|
||||||
|
Bader-eddine Ouaich <49657842+baderouaich@users.noreply.github.com>
|
||||||
|
Baffin Lee <baffinlee@gmail.com>
|
||||||
|
Ben Ashbaugh <ben.ashbaugh@intel.com>
|
||||||
|
Ben Nortier <bjnortier@gmail.com>
|
||||||
|
Benjamin Heiniger <benjamin.heiniger@bluewin.ch>
|
||||||
|
Bernhard M. Wiedemann <githubbmwprimary@lsmod.de>
|
||||||
|
Binozo <70137898+Binozo@users.noreply.github.com>
|
||||||
|
Bo-Yi Wu <appleboy.tw@gmail.com>
|
||||||
|
Boris Bliznioukov <blib@mail.com>
|
||||||
|
Borislav Stanimirov <b.stanimirov@abv.bg>
|
||||||
|
Brad Murray <59848399+bradmurray-dt@users.noreply.github.com>
|
||||||
|
Brian Murray <brian@bmurray.ca>
|
||||||
|
CRD716 <crd716@gmail.com>
|
||||||
|
Canis Lupus <Canis-UK@users.noreply.github.com>
|
||||||
|
Carlos Zoido <mrgalleta@gmail.com>
|
||||||
|
Carolinabanana <140120812+Carolinabanana@users.noreply.github.com>
|
||||||
|
CarterLi999 <664681047@qq.com>
|
||||||
|
ChangSeok Oh <shivamidow@users.noreply.github.com>
|
||||||
|
Changyeon Kim <cyzero.kim@samsung.com>
|
||||||
|
Chaoqun <27287694+OpenWaygate@users.noreply.github.com>
|
||||||
|
Charles Xu <63788048+chaxu01@users.noreply.github.com>
|
||||||
|
Charles Xu <charles.xu@arm.com>
|
||||||
|
Chen Xi <xi2.chen@intel.com>
|
||||||
|
Chen Xi <xixichen08@foxmail.com>
|
||||||
|
Chenguang Li <87689256+noemotiovon@users.noreply.github.com>
|
||||||
|
Chia-Hsiang Cheng <88014292+garychia@users.noreply.github.com>
|
||||||
|
Chidi Williams <williamschidi1@gmail.com>
|
||||||
|
Chris Elrod <elrodc@gmail.com>
|
||||||
|
Christian <12550267+iceychris@users.noreply.github.com>
|
||||||
|
Christian Kastner <ckk@kvr.at>
|
||||||
|
Clifford Heath <clifford.heath@gmail.com>
|
||||||
|
Clint Herron <hanclinto@gmail.com>
|
||||||
|
Colin <github@whoisc.cc>
|
||||||
|
Conrad Kramer <conrad@conradkramer.com>
|
||||||
|
Corey Earwood <iamcgn+github@gmail.com>
|
||||||
|
CrispStrobe <154636388+CrispStrobe@users.noreply.github.com>
|
||||||
|
DAN™ <dranger003@gmail.com>
|
||||||
|
DGdev91 <DGdev91@users.noreply.github.com>
|
||||||
|
Damian Czaja <trojan295@protonmail.com>
|
||||||
|
Dan Johansson <164997844+eddnjjn@users.noreply.github.com>
|
||||||
|
Dan Johansson <dan.johansson@arm.com>
|
||||||
|
Daniel Bevenius <daniel.bevenius@gmail.com>
|
||||||
|
Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com>
|
||||||
|
Daniel Ziegenberg <daniel@ziegenberg.at>
|
||||||
|
Daniele <57776841+daniandtheweb@users.noreply.github.com>
|
||||||
|
Dave <dave-fl@users.noreply.github.com>
|
||||||
|
Dave Airlie <airlied@gmail.com>
|
||||||
|
Dave Airlie <airlied@redhat.com>
|
||||||
|
Daven Sanassy <daven@vochlea.co.uk>
|
||||||
|
David <dnhkng@gmail.com>
|
||||||
|
David Thorpe <djt@mutablelogic.com>
|
||||||
|
DavidKorczynski <david@adalogics.com>
|
||||||
|
Davidson Francis <davidsondfgl@gmail.com>
|
||||||
|
Dener Stassun <denerstassun@gmail.com>
|
||||||
|
Dibakar Gope <dibakar.gope@arm.com>
|
||||||
|
Didzis Gosko <didzis@users.noreply.github.com>
|
||||||
|
Diego Devesa <slarengh@gmail.com>
|
||||||
|
Digipom <admin@digipom.com>
|
||||||
|
Dimo <dimo@ieee.org>
|
||||||
|
Djip007 <3705339+Djip007@users.noreply.github.com>
|
||||||
|
Djip007 <djip.perois@free.fr>
|
||||||
|
Dody Suria Wijaya <dodysw@gmail.com>
|
||||||
|
Dou Xinpeng <15529241576@163.com>
|
||||||
|
Dou Xinpeng <81913537+Dou-Git@users.noreply.github.com>
|
||||||
|
Dr. Tom Murphy VII Ph.D <499244+tom7@users.noreply.github.com>
|
||||||
|
Duncan McConnell <ddmcconnell4@gmail.com>
|
||||||
|
Egor Egorov <me@egorfine.com>
|
||||||
|
Elkana Bardugo <ttv200@gmail.com>
|
||||||
|
Emmanuel Schmidbauer <eschmidbauer@gmail.com>
|
||||||
|
Engininja2 <139037756+Engininja2@users.noreply.github.com>
|
||||||
|
Eric Curtin <ericcurtin17@gmail.com>
|
||||||
|
Eric Swanson <eswanson@alloscomp.com>
|
||||||
|
Eric Tendian <erictendian@gmail.com>
|
||||||
|
Eric Zhang <34133756+EZForever@users.noreply.github.com>
|
||||||
|
Erik Scholz <Green-Sky@users.noreply.github.com>
|
||||||
|
Evan Jones <evan.q.jones@gmail.com>
|
||||||
|
Evan Martin <evan.martin@gmail.com>
|
||||||
|
Eve <139727413+netrunnereve@users.noreply.github.com>
|
||||||
|
Evgeny Kuznetsov <evgeny@kuznetsov.md>
|
||||||
|
F1L1P <78918286+F1L1Pv2@users.noreply.github.com>
|
||||||
|
Faisal Zaghloul <quic_fzaghlou@quicinc.com>
|
||||||
|
Fangjun Kuang <csukuangfj@gmail.com>
|
||||||
|
Felix <stenbackfelix@gmail.com>
|
||||||
|
Finn Voorhees <finnvoorhees@gmail.com>
|
||||||
|
FirstTimeEZ <179362031+FirstTimeEZ@users.noreply.github.com>
|
||||||
|
FlippFuzz <41221030+FlippFuzz@users.noreply.github.com>
|
||||||
|
Frankie Robertson <frankier@users.noreply.github.com>
|
||||||
|
Gang Chen <goncha@gmail.com>
|
||||||
|
Gavin Cai <gavin1818@hotmail.com>
|
||||||
|
George Hindle <george@georgehindle.com>
|
||||||
|
Georgi Gerganov <ggerganov@gmail.com>
|
||||||
|
Gilad S <7817232+giladgd@users.noreply.github.com>
|
||||||
|
Gilad S <giladgd@users.noreply.github.com>
|
||||||
|
Gilad S. <7817232+giladgd@users.noreply.github.com>
|
||||||
|
GitAritron <103900385+GitAritron@users.noreply.github.com>
|
||||||
|
GiviMAD <GiviMAD@users.noreply.github.com>
|
||||||
|
Gleicon Moraes <gleicon@gmail.com>
|
||||||
|
Gregor Jasny <gjasny@googlemail.com>
|
||||||
|
Guillaume Wenzek <gwenzek@users.noreply.github.com>
|
||||||
|
HY. Kelvin Lee <34256578+hykelvinlee42@users.noreply.github.com>
|
||||||
|
Halalaluyafail3 <55773281+Halalaluyafail3@users.noreply.github.com>
|
||||||
|
Hang <bebound@gmail.com>
|
||||||
|
Haus1 <haus.xda@gmail.com>
|
||||||
|
Herman Semenov <GermanAizek@yandex.ru>
|
||||||
|
HimariO <dsfhe49854@gmail.com>
|
||||||
|
Hong Bo PENG <penghb@cn.ibm.com>
|
||||||
|
Hrishikesh Barman <geekodour@users.noreply.github.com>
|
||||||
|
Hugo <hugo@whynothugo.nl>
|
||||||
|
Ian Bicking <ian@ianbicking.org>
|
||||||
|
Ian Bull <irbull@eclipsesource.com>
|
||||||
|
Ihar Hrachyshka <ihrachys@redhat.com>
|
||||||
|
Ikko Ashimine <eltociear@gmail.com>
|
||||||
|
Ikko Eltociear Ashimine <eltociear@gmail.com>
|
||||||
|
InconsolableCellist <23345188+InconsolableCellist@users.noreply.github.com>
|
||||||
|
Ismatulla Mansurov <47342870+sapoepsilon@users.noreply.github.com>
|
||||||
|
Ivan <nekotekina@gmail.com>
|
||||||
|
Ivan Filipov <159561759+vanaka11@users.noreply.github.com>
|
||||||
|
Ivan Gorin <ivangorin21@gmail.com>
|
||||||
|
Ivo von Putzer Reibegg <ivo.putzer@gmail.com>
|
||||||
|
JJ <103335846+computerscienceiscool@users.noreply.github.com>
|
||||||
|
Jack Mousseau <jmousseau@users.noreply.github.com>
|
||||||
|
JacobLinCool <jacoblincool@gmail.com>
|
||||||
|
Jakub Ráček <blizzcz@gmail.com>
|
||||||
|
Jared Van Bortel <jared@nomic.ai>
|
||||||
|
Jay Binks <jaybinks@gmail.com>
|
||||||
|
Jayant <jayantyadav202@gmail.com>
|
||||||
|
Jeff Bolz <jbolz@nvidia.com>
|
||||||
|
Jeroen Mostert <jeroen.mostert@cm.com>
|
||||||
|
Jhen-Jie Hong <developer@jhen.me>
|
||||||
|
Jhen-Jie Hong <iainst0409@gmail.com>
|
||||||
|
JidongZhang-THU <1119708529@qq.com>
|
||||||
|
Jo Liss <joliss42@gmail.com>
|
||||||
|
Joe Todd <joe.todd@codeplay.com>
|
||||||
|
Johan <jr.raffin@gmail.com>
|
||||||
|
Johannes Gäßler <johannesg@5d6.de>
|
||||||
|
John Balis <phobossystems@gmail.com>
|
||||||
|
JohnnyB <jboero@users.noreply.github.com>
|
||||||
|
Jonathan Soo <jcsoo@agora.com>
|
||||||
|
Jonno <1160532+razodactyl@users.noreply.github.com>
|
||||||
|
Joonas Pihlajamaa <joonas.pihlajamaa@iki.fi>
|
||||||
|
Jose <34888496+Jerry-Master@users.noreply.github.com>
|
||||||
|
Josh Bleecher Snyder <josharian@gmail.com>
|
||||||
|
Josscii <jossciiweiyi@gmail.com>
|
||||||
|
Judd <foldl@users.noreply.github.com>
|
||||||
|
Jumper775 <78500318+jumpers775@users.noreply.github.com>
|
||||||
|
Jun Hee Yoo <contact.jhyoo@gmail.com>
|
||||||
|
Junil Kim <logyourself@gmail.com>
|
||||||
|
Justina Cho <justcho5@gmail.com>
|
||||||
|
Justine Tunney <jtunney@gmail.com>
|
||||||
|
Justine Tunney <jtunney@mozilla.com>
|
||||||
|
KITAITI Makoto <KitaitiMakoto@gmail.com>
|
||||||
|
KP Kaiser <kirk@zothcorp.com>
|
||||||
|
Kamilake <exjang0@gmail.com>
|
||||||
|
Karol Kontny <82021046+kkontny@users.noreply.github.com>
|
||||||
|
Karthick <j.karthic2004@gmail.com>
|
||||||
|
Kartik Saranathan <278928+Kartiku@users.noreply.github.com>
|
||||||
|
Kasumi <90275229+kasumi-1@users.noreply.github.com>
|
||||||
|
Kawrakow <48489457+ikawrakow@users.noreply.github.com>
|
||||||
|
Kendrick Taylor <kendrick@circuitsix.com>
|
||||||
|
Kevin Brothaler <admin@digipom.com>
|
||||||
|
Kevin Gibbons <bakkot@gmail.com>
|
||||||
|
Konosuke Sakai <konosuke@konosuke.work>
|
||||||
|
Konstantin Zhuravlyov <konstantin.zhuravlyov@amd.com>
|
||||||
|
Kreijstal <rainb@tfwno.gf>
|
||||||
|
Kylin <56434533+KyL0N@users.noreply.github.com>
|
||||||
|
LBlue <153975653+lbluep@users.noreply.github.com>
|
||||||
|
Larry Battle <larry.battle.tech@gmail.com>
|
||||||
|
Laytan Laats <laytanlaats@hotmail.com>
|
||||||
|
Leo Moll <leo.moll@yeasoft.com>
|
||||||
|
Lexevolution <31176843+Lexevolution@users.noreply.github.com>
|
||||||
|
LittleLoli <26589867+WhichWho@users.noreply.github.com>
|
||||||
|
Lucas Zanek <57494138+LucasZNK@users.noreply.github.com>
|
||||||
|
Luis Herrera <herrera-luis@users.noreply.github.com>
|
||||||
|
Lukas Rist <glaslos@gmail.com>
|
||||||
|
M. A. Ali <73258591+MightyStud@users.noreply.github.com>
|
||||||
|
M. Eren Akbiyik <erenakbiyik@gmail.com>
|
||||||
|
Ma Mingfei <mingfei.ma@intel.com>
|
||||||
|
Maciek <maciek.mab122@gmail.com>
|
||||||
|
Mahesh Madhav <67384846+heshpdx@users.noreply.github.com>
|
||||||
|
Marcin Mielniczuk <marmistrz.dev@zoho.eu>
|
||||||
|
Mark Karpelès <MagicalTux@users.noreply.github.com>
|
||||||
|
Mark Zhuang <zhuangqiubin@gmail.com>
|
||||||
|
Markus Tavenrath <mtavenrath@users.noreply.github.com>
|
||||||
|
Martin Delille <martin@delille.org>
|
||||||
|
Martin Warnaar <martinwarnaar@gmail.com>
|
||||||
|
Masaya, Kato <62578291+msy-kato@users.noreply.github.com>
|
||||||
|
Matheus de Sousa <23645013+keyehzy@users.noreply.github.com>
|
||||||
|
Mathieu Baudier <mbaudier@argeo.org>
|
||||||
|
Mathijs de Bruin <mathijs@mathijsfietst.nl>
|
||||||
|
Matija Pevec <mightymatth@users.noreply.github.com>
|
||||||
|
Matt Stephenson <mstephenson6@users.noreply.github.com>
|
||||||
|
Max Krasnyansky <max.krasnyansky@gmail.com>
|
||||||
|
Max Krasnyansky <quic_maxk@quicinc.com>
|
||||||
|
Maximiliano Levi <8160966+maxilevi@users.noreply.github.com>
|
||||||
|
Meng, Hengyu <hengyu.meng@intel.com>
|
||||||
|
Mengqing Cao <cmq0113@163.com>
|
||||||
|
Michael Podvitskiy <podvitskiymichael@gmail.com>
|
||||||
|
Michael Rienstra <mrienstra@gmail.com>
|
||||||
|
Mikhail Grigorev <sleuthhound@gmail.com>
|
||||||
|
Mohammadreza Hendiani <hendiani.mohammadreza@gmail.com>
|
||||||
|
Mohit Agarwal <mohit@sdf.org>
|
||||||
|
Molly Sophia <mollysophia379@gmail.com>
|
||||||
|
Murilo Santana <mvrilo@gmail.com>
|
||||||
|
NETZkultur GmbH <mulholland@netzkultur.de>
|
||||||
|
Natsu <chino@hotococoa.moe>
|
||||||
|
Neil Chudleigh <nchudleigh@users.noreply.github.com>
|
||||||
|
Neo Zhang <14088817+arthw@users.noreply.github.com>
|
||||||
|
Neo Zhang Jianyu <jianyu.zhang@intel.com>
|
||||||
|
Neuman Vong <neuman.vong@gmail.com>
|
||||||
|
Nicholai Tukanov <nicholaitukanov@gmail.com>
|
||||||
|
Nicholas Albion <nalbion@yahoo.com>
|
||||||
|
Nico Bosshard <nico@bosshome.ch>
|
||||||
|
Nicolò Scipione <nicolo.scipione@codeplay.com>
|
||||||
|
Niels Mayer <Niels.Mayer@gmail.com>
|
||||||
|
Nikita Sarychev <42014488+sARY77@users.noreply.github.com>
|
||||||
|
Nikolaj Olsson <nikse.dk@gmail.com>
|
||||||
|
Okabintaro <103938900+Okabintaro@users.noreply.github.com>
|
||||||
|
Oleg Sidorov <me@whitebox.io>
|
||||||
|
Oleg Sidorov <oleg@sidorov.nl>
|
||||||
|
Olivier Chafik <ochafik@users.noreply.github.com>
|
||||||
|
Ondrej Kokes <ondrej.kokes@gmail.com>
|
||||||
|
Ouadie EL FAROUKI <ouadie.elfarouki@codeplay.com>
|
||||||
|
PAB <pierreantoine.bannier@gmail.com>
|
||||||
|
Paul Tsochantaris <ptsochantaris@icloud.com>
|
||||||
|
Pedro Probst <pprobst@insiberia.net>
|
||||||
|
Peng <hzp1024@qq.com>
|
||||||
|
Peter <peter277@users.noreply.github.com>
|
||||||
|
Philipp Zabel <philipp.zabel@gmail.com>
|
||||||
|
Philippe Normand <phil@base-art.net>
|
||||||
|
Philippe Normand <philn@igalia.com>
|
||||||
|
Plamen Minev <pacominev@gmail.com>
|
||||||
|
Prashant Vithule <119530321+Vithulep@users.noreply.github.com>
|
||||||
|
Przemysław Pawełczyk <przemoc@gmail.com>
|
||||||
|
Qianhe Chen <54462604+chenqianhe@users.noreply.github.com>
|
||||||
|
R0CKSTAR <xiaodong.ye@mthreads.com>
|
||||||
|
R0CKSTAR <yeahdongcn@gmail.com>
|
||||||
|
Radoslav Gerganov <rgerganov@gmail.com>
|
||||||
|
Radosław Gryta <radek.gryta@gmail.com>
|
||||||
|
Rahul Vadhyar <107788610+RahulVadhyar@users.noreply.github.com>
|
||||||
|
Raiya Araki <83504221+rai62@users.noreply.github.com>
|
||||||
|
Reinforce-II <fate@eastal.com>
|
||||||
|
Reinis Muiznieks <muiznieks.reinis@gmail.com>
|
||||||
|
RelatedTitle <r3latedtitle@gmail.com>
|
||||||
|
Rémy Oudompheng <oudomphe@phare.normalesup.org>
|
||||||
|
RhinoDevel <RhinoDevel@users.noreply.github.com>
|
||||||
|
Rich Jones <miserlou@gmail.com>
|
||||||
|
Robert Ormandi <52251610+ormandi@users.noreply.github.com>
|
||||||
|
Robin <robin.xw@hotmail.com>
|
||||||
|
Roddur Dasgupta <roddurd@gmail.com>
|
||||||
|
Roland Rabien <figbug@gmail.com>
|
||||||
|
Romain Biessy <romain.biessy@codeplay.com>
|
||||||
|
Ronsor <ronsor@ronsor.pw>
|
||||||
|
Rotem Dan <rotemdan@gmail.com>
|
||||||
|
Ryan Hitchman <hitchmanr@gmail.com>
|
||||||
|
Ryan Metcalfe <107415876+RyanMetcalfeInt8@users.noreply.github.com>
|
||||||
|
RyanChang <ftes90015@gmail.com>
|
||||||
|
SRHMorris <69468379+SRHMorris@users.noreply.github.com>
|
||||||
|
SXX <sxx1136965276@gmail.com>
|
||||||
|
Sacha Arbonel <sacha.arbonel@hotmail.fr>
|
||||||
|
Salman Faroz <stsfaroz@gmail.com>
|
||||||
|
Salvatore Mesoraca <s.mesoraca16@gmail.com>
|
||||||
|
Sam <49637763+Onlyartist9@users.noreply.github.com>
|
||||||
|
Sam Pullara <spullara@gmail.com>
|
||||||
|
Samuel Durante <44513615+samueldurantes@users.noreply.github.com>
|
||||||
|
Sanchit Gandhi <93869735+sanchit-gandhi@users.noreply.github.com>
|
||||||
|
Sandro Hanea <40202887+sandrohanea@users.noreply.github.com>
|
||||||
|
Sergio López <slp@redhat.com>
|
||||||
|
Sergio López <slp@sinrega.org>
|
||||||
|
Shanshan Shen <467638484@qq.com>
|
||||||
|
Shijie <821898965@qq.com>
|
||||||
|
Shupei Fan <dymarkfan@outlook.com>
|
||||||
|
Siddharth Ramakrishnan <srr2141@columbia.edu>
|
||||||
|
Sigbjørn Skjæret <sigbjorn.skjaeret@scala.com>
|
||||||
|
Simon Moisselin <simon.moisstoll@gmail.com>
|
||||||
|
Sindre Sorhus <sindresorhus@gmail.com>
|
||||||
|
Slava Primenko <primenko.s@gmail.com>
|
||||||
|
Srihari-mcw <96763064+Srihari-mcw@users.noreply.github.com>
|
||||||
|
Stavros Panakakis <53979866+Stavrospanakakis@users.noreply.github.com>
|
||||||
|
Stefan Sydow <s.sydow@heinlein-video.de>
|
||||||
|
Stefan Sydow <stefan@sydow.email>
|
||||||
|
Syahmi Azhar <prsyahmi@gmail.com>
|
||||||
|
Syed Jafri <syedjafri97@gmail.com>
|
||||||
|
Sơn Phan Trung <phantrungson17@gmail.com>
|
||||||
|
Taisei Mima <bhbstar.me@gmail.com>
|
||||||
|
Takeshi Inoue <inoue.takeshi@gmail.com>
|
||||||
|
Tamotsu Takahashi <ttakah+github@gmail.com>
|
||||||
|
Taras Glek <taras@thegp.com>
|
||||||
|
Tauseef Mohiuddin <35351464+tauseefmohammed2@users.noreply.github.com>
|
||||||
|
Thamster <Thamster@users.noreply.github.com>
|
||||||
|
Thijs Raymakers <thijs@raymakers.nl>
|
||||||
|
Thomas Fitzsimmons <fitzsim@fitzsim.org>
|
||||||
|
Tiago Fassoni <tiagofassoni@users.noreply.github.com>
|
||||||
|
Tienshiao Ma <tienshiao@tienshiao.org>
|
||||||
|
Tim Miller <drasticactions@users.noreply.github.com>
|
||||||
|
Timothy Cronin <40186632+4imothy@users.noreply.github.com>
|
||||||
|
Tobrun <tobrun.van.nuland@gmail.com>
|
||||||
|
Todd <taf2@users.noreply.github.com>
|
||||||
|
Toliver <teejae@gmail.com>
|
||||||
|
Tong Li <31761981+litongjava@users.noreply.github.com>
|
||||||
|
Tony Wasserka <4840017+neobrain@users.noreply.github.com>
|
||||||
|
Topping1 <78745143+Topping1@users.noreply.github.com>
|
||||||
|
Travis Cline <travis.cline@gmail.com>
|
||||||
|
UEXTM.com <84163508+uextm@users.noreply.github.com>
|
||||||
|
UsernamesLame <156965854+UsernamesLame@users.noreply.github.com>
|
||||||
|
Vadim Peretokin <vperetokin@hey.com>
|
||||||
|
Valentin Gosu <1454649+valenting@users.noreply.github.com>
|
||||||
|
Vin Misra <vinith@alum.mit.edu>
|
||||||
|
Vulcan <93451215+trholding@users.noreply.github.com>
|
||||||
|
WhiteOlivierus <36532695+WhiteOlivierus@users.noreply.github.com>
|
||||||
|
William Tambellini <william.tambellini@gmail.com>
|
||||||
|
William Tambellini <wtambellini@sdl.com>
|
||||||
|
Wilson Silva <wilson.dsigns@gmail.com>
|
||||||
|
Xiang (Kevin) Li <kevinli020508@gmail.com>
|
||||||
|
Xiao-Yong Jin <jinxiaoyong@gmail.com>
|
||||||
|
XiaotaoChen <chenxiaotao1234@gmail.com>
|
||||||
|
Xingchen Song(宋星辰) <xingchensong1996@163.com>
|
||||||
|
Xinpeng Dou <81913537+Dou-Git@users.noreply.github.com>
|
||||||
|
Xuan Son Nguyen <thichthat@gmail.com>
|
||||||
|
Yajing Tang <phillis@google.com>
|
||||||
|
Yang Shen <aplshenyang@gmail.com>
|
||||||
|
Yunès <jean.baptiste.yunes@free.fr>
|
||||||
|
Yuri Khrustalev <ykhrustalev@users.noreply.github.com>
|
||||||
|
Yusuf Redžić <48274562+redzic@users.noreply.github.com>
|
||||||
|
ZaBlazzingZephyrus <119159668+blazingzephyr@users.noreply.github.com>
|
||||||
|
Zhenwei Jin <109658203+kylo5aby@users.noreply.github.com>
|
||||||
|
Zhiyuan Li <lizhiyuan@uniartisan.com>
|
||||||
|
Zhiyuan Li <uniartisan2017@gmail.com>
|
||||||
|
Zigfrid Zvezdin <ziggerZZ@gmail.com>
|
||||||
|
Zollner <24618122+Zolliner@users.noreply.github.com>
|
||||||
|
a3sh <38979186+A3shTnT@users.noreply.github.com>
|
||||||
|
ag2s20150909 <19373730+ag2s20150909@users.noreply.github.com>
|
||||||
|
agray3 <agray3@users.noreply.github.com>
|
||||||
|
ai-at-home <149282006+ai-at-home@users.noreply.github.com>
|
||||||
|
aldorof <aldorof@users.noreply.github.com>
|
||||||
|
alonfaraj <alonfaraj@gmail.com>
|
||||||
|
amd-dwang <dong.wang@amd.com>
|
||||||
|
amritahs-ibm <amritahs@linux.vnet.ibm.com>
|
||||||
|
andypayne <apayne@gmail.com>
|
||||||
|
ardfork <134447697+ardfork@users.noreply.github.com>
|
||||||
|
arizhih <40765267+arizhih@users.noreply.github.com>
|
||||||
|
automaticcat <daogiatuank54@gmail.com>
|
||||||
|
bandoti <141645996+bandoti@users.noreply.github.com>
|
||||||
|
be-next <jerome.ramette@gmail.com>
|
||||||
|
bert hubert <bert@hubertnet.nl>
|
||||||
|
billyct <billy_allen@126.com>
|
||||||
|
bmwl <brian.marshall@tolko.com>
|
||||||
|
bobqianic <129547291+bobqianic@users.noreply.github.com>
|
||||||
|
bocytko <bocytko+github@gmail.com>
|
||||||
|
boolemancer <48014766+boolemancer@users.noreply.github.com>
|
||||||
|
boolemancer <boolemancer@gmail.com>
|
||||||
|
bradmit <151883577+bradmit@users.noreply.github.com>
|
||||||
|
brunofaustino <b.fa.amorim@gmail.com>
|
||||||
|
bssrdf <merlintiger@hotmail.com>
|
||||||
|
byte-6174 <88070277+byte-6174@users.noreply.github.com>
|
||||||
|
cdosoftei <ciprian.dosoftei@gmail.com>
|
||||||
|
clach04 <Chris.Clark@actian.com>
|
||||||
|
compilade <113953597+compilade@users.noreply.github.com>
|
||||||
|
compilade <git@compilade.net>
|
||||||
|
conradg <conradjgodfrey@gmail.com>
|
||||||
|
crummyh <elijah@crums.us>
|
||||||
|
ddpasa <112642920+ddpasa@users.noreply.github.com>
|
||||||
|
denersc <denerstassun@gmail.com>
|
||||||
|
dscripka <dscripka@users.noreply.github.com>
|
||||||
|
duthils <duthils@duthils.net>
|
||||||
|
ecneladis <ecneladis@users.noreply.github.com>
|
||||||
|
faker <nspyia2002@gmail.com>
|
||||||
|
fitzsim <fitzsim@fitzsim.org>
|
||||||
|
fj-y-saito <85871716+fj-y-saito@users.noreply.github.com>
|
||||||
|
fraxy-v <65565042+fraxy-v@users.noreply.github.com>
|
||||||
|
genevera (she/her) <genevera@users.noreply.github.com>
|
||||||
|
geniusnut <geniusnut@gmail.com>
|
||||||
|
gilbertgong <gilbert.gong@gmail.com>
|
||||||
|
gn64 <yukikaze.jp@gmail.com>
|
||||||
|
goldwaving <77494627+goldwaving@users.noreply.github.com>
|
||||||
|
greeshmay <greeshmay@gmail.com>
|
||||||
|
haopeng <657407891@qq.com>
|
||||||
|
hipudding <huafengchun@gmail.com>
|
||||||
|
hsinhoyeh <yhh92u@gmail.com>
|
||||||
|
hydai <z54981220@gmail.com>
|
||||||
|
iamthad <thadeus.j.fleming@gmail.com>
|
||||||
|
issixx <46835150+issixx@users.noreply.github.com>
|
||||||
|
james wolf <contractorwolf@hotmail.com>
|
||||||
|
jdomke <28772296+jdomke@users.noreply.github.com>
|
||||||
|
jettoblack <jettoblack@gmail.com>
|
||||||
|
jiez <373447296@qq.com>
|
||||||
|
joecryptotoo <80373433+joecryptotoo@users.noreply.github.com>
|
||||||
|
jorismertz <35079666+jorismertz@users.noreply.github.com>
|
||||||
|
junchao-loongson <68935141+junchao-loongson@users.noreply.github.com>
|
||||||
|
junkfood <69683722+JunkFood02@users.noreply.github.com>
|
||||||
|
jwijffels <jwijffels@bnosac.be>
|
||||||
|
k.h.lai <adrian.k.h.lai@outlook.com>
|
||||||
|
kamranjon <kamranjon@gmail.com>
|
||||||
|
katsu560 <katsu560oo-@docomo.ne.jp>
|
||||||
|
kennethge <57784063+kenneth-ge@users.noreply.github.com>
|
||||||
|
keyehzy <msamuel@aluno.puc-rio.br>
|
||||||
|
kunnis <kunnis@users.noreply.github.com>
|
||||||
|
l3utterfly <gc.pthzfoldr@gmail.com>
|
||||||
|
leejet <leejet714@gmail.com>
|
||||||
|
leo-pony <nengjunma@outlook.com>
|
||||||
|
lhez <quic_lih@quicinc.com>
|
||||||
|
litong <31761981+litongjava@users.noreply.github.com>
|
||||||
|
liuwei-git <14815172+liuwei-git@users.noreply.github.com>
|
||||||
|
lnyan <lkwq007@gmail.com>
|
||||||
|
luoyu-intel <yu.luo@intel.com>
|
||||||
|
m.bell <m.bell@techsmith.com>
|
||||||
|
mahorozte <41834471+mahorozte@users.noreply.github.com>
|
||||||
|
mashizora <30516315+mashizora@users.noreply.github.com>
|
||||||
|
matt23654 <matthew.webber@protonmail.com>
|
||||||
|
matteo <matteogeniaccio@yahoo.it>
|
||||||
|
mgrachten <maarten@grachten.eu>
|
||||||
|
mkiol <mkiol@users.noreply.github.com>
|
||||||
|
mky_coder <47767389+mkycoder@users.noreply.github.com>
|
||||||
|
novag <7754358+novag@users.noreply.github.com>
|
||||||
|
pajowu <pajowu@pajowu.de>
|
||||||
|
pengxin99 <pengxin.yuan@intel.com>
|
||||||
|
petterreinholdtsen <pere-github@hungry.com>
|
||||||
|
polarmoon <90010972+polarmoon@users.noreply.github.com>
|
||||||
|
rlapray <lapray.romain@gmail.com>
|
||||||
|
sandrohanea <40202887+sandrohanea@users.noreply.github.com>
|
||||||
|
semiformal-net <84111142+semiformal-net@users.noreply.github.com>
|
||||||
|
shibukazu <61775791+shibukazu@users.noreply.github.com>
|
||||||
|
shikokuchuo <53399081+shikokuchuo@users.noreply.github.com>
|
||||||
|
slaren <slarengh@gmail.com>
|
||||||
|
slashlib <slashlib@users.noreply.github.com>
|
||||||
|
snadampal <87143774+snadampal@users.noreply.github.com>
|
||||||
|
someone13574 <81528246+someone13574@users.noreply.github.com>
|
||||||
|
st-gr <38470677+st-gr@users.noreply.github.com>
|
||||||
|
stduhpf <stephduh@live.fr>
|
||||||
|
stormofice <58337328+stormofice@users.noreply.github.com>
|
||||||
|
texmex76 <40733439+texmex76@users.noreply.github.com>
|
||||||
|
thefinaldegree <thefinaldegree@gmail.com>
|
||||||
|
thewh1teagle <61390950+thewh1teagle@users.noreply.github.com>
|
||||||
|
toboil-features <160222185+toboil-features@users.noreply.github.com>
|
||||||
|
trixirt <trix@redhat.com>
|
||||||
|
ulatekh <ulatekh@yahoo.com>
|
||||||
|
undef <undefdev@gmail.com>
|
||||||
|
uvos <devnull@uvos.xyz>
|
||||||
|
uvos <philipp@uvos.xyz>
|
||||||
|
valVk <valVk@users.noreply.github.com>
|
||||||
|
venkr <venkateshrameshkumar+1@gmail.com>
|
||||||
|
vicalloy <zbirder@gmail.com>
|
||||||
|
wangshuai09 <391746016@qq.com>
|
||||||
|
woachk <24752637+woachk@users.noreply.github.com>
|
||||||
|
xctan <axunlei@gmail.com>
|
||||||
|
xdrudis <xavierdrudis@yahoo.es>
|
||||||
|
yuri@FreeBSD <yuri@FreeBSD>
|
||||||
|
zhangjixiong <code.zjx@gmail.com>
|
||||||
|
zhentaoyu <zhentao.yu@intel.com>
|
||||||
|
zhouwg <6889919+zhouwg@users.noreply.github.com>
|
||||||
|
zhouwg <zhouwg2000@gmail.com>
|
||||||
|
谢乃闻 <sienaiwun@users.noreply.github.com>
|
||||||
|
布客飞龙 <562826179@qq.com>
|
||||||
|
Артём Земляк <azemlyak@smart-consulting.ru>
|
||||||
324
CMakeLists.txt
Normal file
324
CMakeLists.txt
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.5) # for add_link_options and implicit target directories.
|
||||||
|
project("whisper.cpp" C CXX)
|
||||||
|
include(CheckIncludeFileCXX)
|
||||||
|
|
||||||
|
### whisper.cpp version
|
||||||
|
set(WHISPER_VERSION_MAJOR 1)
|
||||||
|
set(WHISPER_VERSION_MINOR 9)
|
||||||
|
set(WHISPER_VERSION_PATCH 4)
|
||||||
|
set(WHISPER_VERSION_BASE "${WHISPER_VERSION_MAJOR}.${WHISPER_VERSION_MINOR}.${WHISPER_VERSION_PATCH}")
|
||||||
|
|
||||||
|
# whether this is a development/nightly build
|
||||||
|
# set this to OFF when making a release from a release tag (vX.Y.Z)
|
||||||
|
# ref: https://github.com/ggml-org/ggml/discussions/1579
|
||||||
|
option(WHISPER_BUILD_IS_DEV "whisper: dev build" ON)
|
||||||
|
|
||||||
|
if (WHISPER_BUILD_IS_DEV)
|
||||||
|
set(WHISPER_VERSION "${WHISPER_VERSION_BASE}-dev")
|
||||||
|
else()
|
||||||
|
# TODO: check that the current commit is tagged correctly according to the version specified above
|
||||||
|
set(WHISPER_VERSION "${WHISPER_VERSION_BASE}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
message(STATUS "whisper.cpp version: ${WHISPER_VERSION}")
|
||||||
|
|
||||||
|
#set(CMAKE_WARN_DEPRECATED YES)
|
||||||
|
set(CMAKE_WARN_UNUSED_CLI YES)
|
||||||
|
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
if (NOT XCODE AND NOT MSVC AND NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
||||||
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Add path to modules
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
|
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
set(WHISPER_STANDALONE ON)
|
||||||
|
|
||||||
|
include(git-vars)
|
||||||
|
|
||||||
|
# configure project version
|
||||||
|
configure_file(${CMAKE_SOURCE_DIR}/bindings/javascript/package-tmpl.json ${CMAKE_SOURCE_DIR}/bindings/javascript/package.json @ONLY)
|
||||||
|
else()
|
||||||
|
set(WHISPER_STANDALONE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (EMSCRIPTEN)
|
||||||
|
set(BUILD_SHARED_LIBS_DEFAULT OFF)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
option(WHISPER_WASM_SINGLE_FILE "whisper: embed WASM inside the generated whisper.js" ON)
|
||||||
|
|
||||||
|
# TODO: without these, we get the following error:
|
||||||
|
# wasm-ld: error: --shared-memory is disallowed by whisper.cpp.o because it was not compiled with 'atomics' or 'bulk-memory' features.
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=5242880")
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s TOTAL_STACK=5242880")
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated")
|
||||||
|
else()
|
||||||
|
if (MINGW)
|
||||||
|
set(BUILD_SHARED_LIBS_DEFAULT OFF)
|
||||||
|
else()
|
||||||
|
set(BUILD_SHARED_LIBS_DEFAULT ON)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(BUILD_SHARED_LIBS "build shared libraries" ${BUILD_SHARED_LIBS_DEFAULT})
|
||||||
|
|
||||||
|
#
|
||||||
|
# option list
|
||||||
|
#
|
||||||
|
|
||||||
|
# debug
|
||||||
|
option(WHISPER_ALL_WARNINGS "whisper: enable all compiler warnings" ON)
|
||||||
|
option(WHISPER_ALL_WARNINGS_3RD_PARTY "whisper: enable all compiler warnings in 3rd party libs" OFF)
|
||||||
|
|
||||||
|
# build
|
||||||
|
option(WHISPER_FATAL_WARNINGS "whisper: enable -Werror flag" OFF)
|
||||||
|
option(WHISPER_USE_SYSTEM_GGML "whisper: use system-installed GGML library" OFF)
|
||||||
|
option(WHISPER_USE_SYSTEM_LLAMA "whisper: use system-installed llama.cpp library" OFF)
|
||||||
|
|
||||||
|
if (WHISPER_USE_SYSTEM_LLAMA AND NOT WHISPER_USE_SYSTEM_GGML)
|
||||||
|
message(STATUS "WHISPER_USE_SYSTEM_LLAMA=ON: setting WHISPER_USE_SYSTEM_GGML=ON")
|
||||||
|
set(WHISPER_USE_SYSTEM_GGML ON CACHE BOOL "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# sanitizers
|
||||||
|
option(WHISPER_SANITIZE_THREAD "whisper: enable thread sanitizer" OFF)
|
||||||
|
option(WHISPER_SANITIZE_ADDRESS "whisper: enable address sanitizer" OFF)
|
||||||
|
option(WHISPER_SANITIZE_UNDEFINED "whisper: enable undefined sanitizer" OFF)
|
||||||
|
|
||||||
|
# extra artifacts
|
||||||
|
option(WHISPER_BUILD_TESTS "whisper: build tests" ${WHISPER_STANDALONE})
|
||||||
|
option(WHISPER_BUILD_EXAMPLES "whisper: build examples" ${WHISPER_STANDALONE})
|
||||||
|
option(WHISPER_BUILD_SERVER "whisper: build server example" ${WHISPER_STANDALONE})
|
||||||
|
|
||||||
|
# 3rd party libs
|
||||||
|
option(WHISPER_CURL "whisper: use libcurl to download model from an URL" OFF)
|
||||||
|
option(WHISPER_SDL2 "whisper: support for libSDL2" OFF)
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
|
option(WHISPER_COMMON_FFMPEG "whisper: examples link with ffmpeg libs in order to decode more audio formats" OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(WHISPER_COREML "whisper: enable Core ML framework" OFF)
|
||||||
|
option(WHISPER_COREML_ALLOW_FALLBACK "whisper: allow non-CoreML fallback" OFF)
|
||||||
|
option(WHISPER_OPENVINO "whisper: support for OpenVINO" OFF)
|
||||||
|
option(WHISPER_VITISAI "whisper: support for AMD Vitis AI" OFF)
|
||||||
|
|
||||||
|
# Required for relocatable CMake package
|
||||||
|
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-info.cmake)
|
||||||
|
|
||||||
|
# override ggml options
|
||||||
|
set(GGML_SANITIZE_THREAD ${WHISPER_SANITIZE_THREAD})
|
||||||
|
set(GGML_SANITIZE_ADDRESS ${WHISPER_SANITIZE_ADDRESS})
|
||||||
|
set(GGML_SANITIZE_UNDEFINED ${WHISPER_SANITIZE_UNDEFINED})
|
||||||
|
set(GGML_ALL_WARNINGS ${WHISPER_ALL_WARNINGS})
|
||||||
|
set(GGML_FATAL_WARNINGS ${WHISPER_FATAL_WARNINGS})
|
||||||
|
|
||||||
|
# transition helpers
|
||||||
|
function (whisper_option_depr TYPE OLD NEW)
|
||||||
|
if (${OLD})
|
||||||
|
message(${TYPE} "${OLD} is deprecated and will be removed in the future.\nUse ${NEW} instead\n")
|
||||||
|
set(${NEW} ON)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
whisper_option_depr(FATAL_ERROR WHISPER_CUBLAS GGML_CUDA)
|
||||||
|
whisper_option_depr(WARNING WHISPER_CUDA GGML_CUDA)
|
||||||
|
whisper_option_depr(WARNING WHISPER_KOMPUTE GGML_KOMPUTE)
|
||||||
|
whisper_option_depr(WARNING WHISPER_METAL GGML_METAL)
|
||||||
|
whisper_option_depr(WARNING WHISPER_METAL_EMBED_LIBRARY GGML_METAL_EMBED_LIBRARY)
|
||||||
|
whisper_option_depr(WARNING WHISPER_NATIVE GGML_NATIVE)
|
||||||
|
whisper_option_depr(WARNING WHISPER_OPENMP GGML_OPENMP)
|
||||||
|
whisper_option_depr(WARNING WHISPER_RPC GGML_RPC)
|
||||||
|
whisper_option_depr(WARNING WHISPER_SYCL GGML_SYCL)
|
||||||
|
whisper_option_depr(WARNING WHISPER_SYCL_F16 GGML_SYCL_F16)
|
||||||
|
whisper_option_depr(WARNING WHISPER_CCACHE GGML_CCACHE)
|
||||||
|
whisper_option_depr(WARNING WHISPER_FFMPEG WHISPER_COMMON_FFMPEG)
|
||||||
|
|
||||||
|
if (GGML_CUDA AND NOT MSVC)
|
||||||
|
#GGML_CUDA enabled, add the necessary compile options -Wno-deprecated-gpu-targets
|
||||||
|
add_compile_options(-Wno-deprecated-gpu-targets)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# build the library
|
||||||
|
#
|
||||||
|
|
||||||
|
if (NOT TARGET ggml)
|
||||||
|
if (WHISPER_USE_SYSTEM_GGML)
|
||||||
|
find_package(ggml REQUIRED)
|
||||||
|
if (NOT ggml_FOUND)
|
||||||
|
message(FATAL_ERROR "System-installed GGML library not found.")
|
||||||
|
endif()
|
||||||
|
add_library(ggml ALIAS ggml::ggml)
|
||||||
|
else()
|
||||||
|
add_subdirectory(ggml)
|
||||||
|
if(WIN32)
|
||||||
|
# The following adds a _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR macro and is a workaround for
|
||||||
|
# the Windows C++ standard library which does not support constexpr mutexes.
|
||||||
|
# From the release notes://github.com/microsoft/STL/wiki/Changelog
|
||||||
|
# Disable constexpr mutex constructor on Windows
|
||||||
|
# Fixed mutex's constructor to be constexpr. #3824 #4000 #4339
|
||||||
|
# Note: Programs that aren't following the documented restrictions on binary compatibility may encounter
|
||||||
|
# null dereferences in mutex machinery. You must follow this rule:
|
||||||
|
# When you mix binaries built by different supported versions of the toolset, the Redistributable version
|
||||||
|
# must be at least as new as the latest toolset used by any app component.
|
||||||
|
# You can define _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR as an escape hatch.
|
||||||
|
#
|
||||||
|
# Specifically to whisper.cpp this would cause a crash when using the Java bindings.
|
||||||
|
# resulting in a Invalid memory access error.
|
||||||
|
target_compile_definitions(ggml-base PRIVATE _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
# ... otherwise assume ggml is added by a parent CMakeLists.txt
|
||||||
|
endif()
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
#
|
||||||
|
# install
|
||||||
|
#
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
if (NOT DEFINED WHISPER_BUILD_NUMBER)
|
||||||
|
set(WHISPER_BUILD_NUMBER ${BUILD_NUMBER})
|
||||||
|
endif()
|
||||||
|
if (NOT DEFINED WHISPER_BUILD_COMMIT)
|
||||||
|
set(WHISPER_BUILD_COMMIT ${BUILD_COMMIT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(WHISPER_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Location of header files")
|
||||||
|
set(WHISPER_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of library files")
|
||||||
|
set(WHISPER_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Location of binary files")
|
||||||
|
|
||||||
|
get_directory_property(WHISPER_TRANSIENT_DEFINES COMPILE_DEFINITIONS)
|
||||||
|
|
||||||
|
set_target_properties(whisper PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/include/whisper.h)
|
||||||
|
|
||||||
|
install(TARGETS whisper LIBRARY PUBLIC_HEADER)
|
||||||
|
|
||||||
|
target_compile_definitions(whisper PRIVATE
|
||||||
|
WHISPER_VERSION="${WHISPER_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(parakeet PROPERTIES PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/include/parakeet.h)
|
||||||
|
install(TARGETS parakeet LIBRARY PUBLIC_HEADER)
|
||||||
|
|
||||||
|
target_compile_definitions(parakeet PRIVATE
|
||||||
|
PARAKEET_VERSION="${WHISPER_VERSION}"
|
||||||
|
)
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/cmake/whisper-config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/whisper-config.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/whisper
|
||||||
|
PATH_VARS
|
||||||
|
WHISPER_INCLUDE_INSTALL_DIR
|
||||||
|
WHISPER_LIB_INSTALL_DIR
|
||||||
|
WHISPER_BIN_INSTALL_DIR )
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/whisper-config-version.cmake
|
||||||
|
VERSION ${WHISPER_VERSION}
|
||||||
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/whisper-config.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/whisper-config-version.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/whisper)
|
||||||
|
|
||||||
|
configure_file(cmake/whisper.pc.in
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/whisper.pc"
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/whisper.pc"
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||||
|
|
||||||
|
set(PARAKEET_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Location of header files")
|
||||||
|
set(PARAKEET_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of library files")
|
||||||
|
set(PARAKEET_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Location of binary files")
|
||||||
|
|
||||||
|
configure_package_config_file(
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/cmake/parakeet-config.cmake.in
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/parakeet-config.cmake
|
||||||
|
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/parakeet
|
||||||
|
PATH_VARS
|
||||||
|
PARAKEET_INCLUDE_INSTALL_DIR
|
||||||
|
PARAKEET_LIB_INSTALL_DIR
|
||||||
|
PARAKEET_BIN_INSTALL_DIR)
|
||||||
|
|
||||||
|
write_basic_package_version_file(
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/parakeet-config-version.cmake
|
||||||
|
VERSION ${WHISPER_VERSION}
|
||||||
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/parakeet-config.cmake
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/parakeet-config-version.cmake
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/parakeet)
|
||||||
|
|
||||||
|
configure_file(cmake/parakeet.pc.in
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/parakeet.pc"
|
||||||
|
@ONLY)
|
||||||
|
|
||||||
|
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/parakeet.pc"
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||||
|
|
||||||
|
#
|
||||||
|
# programs, examples and tests
|
||||||
|
#
|
||||||
|
|
||||||
|
if (WHISPER_BUILD_TESTS AND NOT CMAKE_JS_VERSION)
|
||||||
|
include(CTest)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
if (WHISPER_BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(examples)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (MSVC)
|
||||||
|
set(MSVC_WARNING_FLAGS
|
||||||
|
/wd4101 # Unreferenced local variable
|
||||||
|
/wd4005 # Macro redefinition
|
||||||
|
/wd4065 # switch statement contains 'default' but no 'case' labels
|
||||||
|
/wd4267 # Conversion from 'size_t' to a smaller type, possible loss of data
|
||||||
|
/wd4244 # Conversion from one type to another type, possible loss of ata
|
||||||
|
/wd4805 # Unsafe mix of type
|
||||||
|
/wd4305 # Truncation from 'type1' to 'type2' (often double to float)
|
||||||
|
/wd4996 # Function or variable may be unsafe/deprecated
|
||||||
|
)
|
||||||
|
function(disable_msvc_warnings target_name)
|
||||||
|
if(TARGET ${target_name})
|
||||||
|
target_compile_options(${target_name} PRIVATE ${MSVC_WARNING_FLAGS})
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if (WHISPER_BUILD_EXAMPLES)
|
||||||
|
disable_msvc_warnings(whisper)
|
||||||
|
disable_msvc_warnings(common)
|
||||||
|
disable_msvc_warnings(common-sdl)
|
||||||
|
disable_msvc_warnings(lsp)
|
||||||
|
disable_msvc_warnings(wchess-core)
|
||||||
|
disable_msvc_warnings(whisper-command)
|
||||||
|
disable_msvc_warnings(whisper-cli)
|
||||||
|
disable_msvc_warnings(whisper-server)
|
||||||
|
disable_msvc_warnings(whisper-stream)
|
||||||
|
disable_msvc_warnings(whisper-talk-llama)
|
||||||
|
disable_msvc_warnings(whisper-bench)
|
||||||
|
disable_msvc_warnings(quantize)
|
||||||
|
disable_msvc_warnings(vad-speech-segments)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
95
CMakePresets.json
Normal file
95
CMakePresets.json
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
{
|
||||||
|
"version": 4,
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "base",
|
||||||
|
"hidden": true,
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build-${presetName}",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
||||||
|
"CMAKE_INSTALL_RPATH": "$ORIGIN;$ORIGIN/.."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sycl-base",
|
||||||
|
"hidden": true,
|
||||||
|
"generator": "Ninja",
|
||||||
|
"binaryDir": "${sourceDir}/build-${presetName}",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
||||||
|
"CMAKE_CXX_COMPILER": "icx",
|
||||||
|
"CMAKE_C_COMPILER": "cl",
|
||||||
|
"GGML_SYCL": "ON",
|
||||||
|
"CMAKE_INSTALL_RPATH": "$ORIGIN;$ORIGIN/.."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "name": "debug", "hidden": true, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } },
|
||||||
|
{ "name": "release", "hidden": true, "cacheVariables": { "CMAKE_BUILD_TYPE": "Release" } },
|
||||||
|
{ "name": "reldbg", "hidden": true, "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } },
|
||||||
|
{ "name": "static", "hidden": true, "cacheVariables": { "GGML_STATIC": "ON" } },
|
||||||
|
{ "name": "sycl_f16", "hidden": true, "cacheVariables": { "GGML_SYCL_F16": "ON" } },
|
||||||
|
{ "name": "vulkan", "hidden": true, "cacheVariables": { "GGML_VULKAN": "ON" } },
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "x64-windows-llvm", "hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/x64-windows-llvm.cmake"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "arm64-windows-llvm", "hidden": true,
|
||||||
|
"architecture": { "value": "arm64", "strategy": "external" },
|
||||||
|
"toolset": { "value": "host=x64", "strategy": "external" },
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/arm64-windows-llvm.cmake"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "arm64-apple-clang", "hidden": true,
|
||||||
|
"architecture": { "value": "arm64", "strategy": "external" },
|
||||||
|
"toolset": { "value": "host=x64", "strategy": "external" },
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/cmake/arm64-apple-clang.cmake"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "x64-linux-gcc", "hidden": true,
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_C_COMPILER": "gcc",
|
||||||
|
"CMAKE_CXX_COMPILER": "g++"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ "name": "x64-linux-gcc-debug", "inherits": [ "base", "x64-linux-gcc", "debug" ] },
|
||||||
|
{ "name": "x64-linux-gcc-release", "inherits": [ "base", "x64-linux-gcc", "release" ] },
|
||||||
|
{ "name": "x64-linux-gcc-reldbg", "inherits": [ "base", "x64-linux-gcc", "reldbg" ] },
|
||||||
|
{ "name": "x64-linux-gcc+static-release", "inherits": [ "base", "x64-linux-gcc", "release", "static" ] },
|
||||||
|
|
||||||
|
{ "name": "arm64-windows-llvm-debug", "inherits": [ "base", "arm64-windows-llvm", "debug" ] },
|
||||||
|
{ "name": "arm64-windows-llvm-release", "inherits": [ "base", "arm64-windows-llvm", "reldbg" ] },
|
||||||
|
{ "name": "arm64-windows-llvm+static-release", "inherits": [ "base", "arm64-windows-llvm", "reldbg", "static" ] },
|
||||||
|
|
||||||
|
{ "name": "arm64-apple-clang-debug", "inherits": [ "base", "arm64-apple-clang", "debug" ] },
|
||||||
|
{ "name": "arm64-apple-clang-release", "inherits": [ "base", "arm64-apple-clang", "reldbg" ] },
|
||||||
|
{ "name": "arm64-apple-clang+static-release", "inherits": [ "base", "arm64-apple-clang", "reldbg", "static" ] },
|
||||||
|
|
||||||
|
{ "name": "x64-windows-llvm-debug", "inherits": [ "base", "x64-windows-llvm", "debug" ] },
|
||||||
|
{ "name": "x64-windows-llvm-release", "inherits": [ "base", "x64-windows-llvm", "release" ] },
|
||||||
|
{ "name": "x64-windows-llvm-reldbg", "inherits": [ "base", "x64-windows-llvm", "reldbg" ] },
|
||||||
|
{ "name": "x64-windows-llvm+static-release", "inherits": [ "base", "x64-windows-llvm", "reldbg", "static" ] },
|
||||||
|
|
||||||
|
{ "name": "x64-windows-msvc-debug", "inherits": [ "base", "debug" ] },
|
||||||
|
{ "name": "x64-windows-msvc-release", "inherits": [ "base", "reldbg" ] },
|
||||||
|
{ "name": "x64-windows-msvc+static-release", "inherits": [ "base", "reldbg", "static" ] },
|
||||||
|
|
||||||
|
{ "name": "x64-windows-sycl-debug", "inherits": [ "sycl-base", "debug" ] },
|
||||||
|
{ "name": "x64-windows-sycl-debug-f16", "inherits": [ "sycl-base", "debug", "sycl_f16" ] },
|
||||||
|
{ "name": "x64-windows-sycl-release", "inherits": [ "sycl-base", "release" ] },
|
||||||
|
{ "name": "x64-windows-sycl-release-f16", "inherits": [ "sycl-base", "release", "sycl_f16" ] },
|
||||||
|
|
||||||
|
{ "name": "x64-windows-vulkan-debug", "inherits": [ "base", "vulkan", "debug" ] },
|
||||||
|
{ "name": "x64-windows-vulkan-release", "inherits": [ "base", "vulkan", "release" ] }
|
||||||
|
]
|
||||||
|
}
|
||||||
176
CONTRIBUTING.md
Normal file
176
CONTRIBUTING.md
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
# Contributors
|
||||||
|
|
||||||
|
The project differentiates between 3 levels of contributors:
|
||||||
|
|
||||||
|
- Contributors: people who have contributed before (no special privileges)
|
||||||
|
- Collaborators (Triage): people with significant contributions, who may be responsible for some parts of the code, and are expected to maintain and review contributions for the code they own
|
||||||
|
- Maintainers: responsible for reviewing and merging PRs, after approval from the code owners
|
||||||
|
|
||||||
|
# AI Usage Policy
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
|
||||||
|
>
|
||||||
|
> Repeated violations of this policy may result in your account being permanently banned from contributing to the project.
|
||||||
|
>
|
||||||
|
> Detailed information regarding permissible and restricted uses of AI can be found in the [AGENTS.md](AGENTS.md) file.
|
||||||
|
|
||||||
|
Code that is initially generated by AI and subsequently edited will still be considered AI-generated. AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for corrections or to expand on verbose modifications that the contributor has already conceptualized (e.g., generating repeated lines with minor variations).
|
||||||
|
|
||||||
|
If AI is used to generate any portion of the code, contributors must adhere to the following requirements:
|
||||||
|
|
||||||
|
1. Explicitly disclose the manner in which AI was employed.
|
||||||
|
2. Perform a comprehensive manual review prior to submitting the pull request.
|
||||||
|
3. Be prepared to explain every line of code they submitted when asked about it by a maintainer.
|
||||||
|
4. It is strictly prohibited to use AI to write your posts for you (bug reports, feature requests, pull request descriptions, Github discussions, responding to humans, ...).
|
||||||
|
|
||||||
|
For more info, please refer to the [AGENTS.md](AGENTS.md) file.
|
||||||
|
|
||||||
|
# Pull requests (for contributors & collaborators)
|
||||||
|
|
||||||
|
Before submitting your PR:
|
||||||
|
- Search for existing PRs to prevent duplicating efforts
|
||||||
|
- whisper.cpp uses the ggml tensor library for model evaluation. If you are unfamiliar with ggml, consider taking a look at the [examples in the ggml repository](https://github.com/ggml-org/ggml/tree/master/examples/). [simple](https://github.com/ggml-org/ggml/tree/master/examples/simple) shows the bare minimum for using ggml. [gpt-2](https://github.com/ggml-org/ggml/tree/master/examples/gpt-2) has minimal implementations for language model inference using GPT-2. [mnist](https://github.com/ggml-org/ggml/tree/master/examples/mnist) demonstrates how to train and evaluate a simple image classifier
|
||||||
|
- Test your changes:
|
||||||
|
- Execute [the full CI locally on your machine](ci/README.md) before publishing
|
||||||
|
- Create separate PRs for each feature or fix:
|
||||||
|
- Avoid combining unrelated changes in a single PR
|
||||||
|
- For intricate features, consider opening a feature request first to discuss and align expectations
|
||||||
|
- If you are a new contributor
|
||||||
|
- Limit your open PRs to 1
|
||||||
|
- Do not submit trivial fixes (e.g. typos, formatting changes)
|
||||||
|
|
||||||
|
After submitting your PR:
|
||||||
|
- Expect requests for modifications to ensure the code meets whisper.cpp's standards for quality and long-term maintainability
|
||||||
|
- Maintainers will rely on your insights and approval when making a final decision to approve and merge a PR
|
||||||
|
- If your PR becomes stale, rebase it on top of latest `master` to get maintainers attention
|
||||||
|
|
||||||
|
# Pull requests (for maintainers)
|
||||||
|
|
||||||
|
- Squash-merge PRs
|
||||||
|
- Use the following format for the squashed commit title: `<module> : <commit title> (#<issue_number>)`. For example: `utils : fix typo in utils.py (#1234)`
|
||||||
|
- Optionally pick a `<module>` from here: https://github.com/ggml-org/llama.cpp/wiki/Modules
|
||||||
|
- Let other maintainers merge their own PRs
|
||||||
|
- When merging a PR, make sure you have a good understanding of the changes
|
||||||
|
- Be mindful of maintenance: most of the work going into a feature happens after the PR is merged. If the PR author is not committed to contribute long-term, someone else needs to take responsibility (you)
|
||||||
|
|
||||||
|
Maintainers reserve the right to decline review or close pull requests for any reason, without any questions, particularly under any of the following conditions:
|
||||||
|
- The proposed change is already mentioned in the roadmap or an existing issue, and it has been assigned to someone.
|
||||||
|
- The pull request duplicates an existing one.
|
||||||
|
- The contributor fails to adhere to this contributing guide or the AI policy.
|
||||||
|
|
||||||
|
# Coding guidelines
|
||||||
|
|
||||||
|
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||||
|
- Always consider cross-compatibility with other operating systems and architectures
|
||||||
|
- Avoid fancy-looking modern STL constructs, use basic `for` loops, avoid templates, keep it simple
|
||||||
|
- Vertical alignment makes things more readable and easier to batch edit
|
||||||
|
- Clean-up any trailing whitespaces, use 4 spaces for indentation, brackets on the same line, `void * ptr`, `int & a`
|
||||||
|
- Use sized integer types such as `int32_t` in the public API, e.g. `size_t` may also be appropriate for allocation sizes or byte offsets
|
||||||
|
- Declare structs with `struct foo {}` instead of `typedef struct foo {} foo`
|
||||||
|
- In C++ code omit optional `struct` and `enum` keyword whenever they are not necessary
|
||||||
|
```cpp
|
||||||
|
// OK
|
||||||
|
llama_context * ctx;
|
||||||
|
const llama_rope_type rope_type;
|
||||||
|
|
||||||
|
// not OK
|
||||||
|
struct llama_context * ctx;
|
||||||
|
const enum llama_rope_type rope_type;
|
||||||
|
```
|
||||||
|
|
||||||
|
_(NOTE: this guideline is yet to be applied to the `whisper.cpp` codebase. New code should follow this guideline.)_
|
||||||
|
|
||||||
|
- Try to follow the existing patterns in the code (indentation, spaces, etc.). In case of doubt use `clang-format` (from clang-tools v15+) to format the added code
|
||||||
|
- For anything not covered in the current guidelines, refer to the [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)
|
||||||
|
- Tensors store data in row-major order. We refer to dimension 0 as columns, 1 as rows, 2 as matrices
|
||||||
|
- Matrix multiplication is unconventional: [`C = ggml_mul_mat(ctx, A, B)`](https://github.com/ggml-org/llama.cpp/blob/880e352277fc017df4d5794f0c21c44e1eae2b84/ggml.h#L1058-L1064) means $C^T = A B^T \Leftrightarrow C = B A^T.$
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# Naming guidelines
|
||||||
|
|
||||||
|
- Use `snake_case` for function, variable and type names
|
||||||
|
- Naming usually optimizes for longest common prefix (see https://github.com/ggml-org/ggml/pull/302#discussion_r1243240963)
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// not OK
|
||||||
|
int small_number;
|
||||||
|
int big_number;
|
||||||
|
|
||||||
|
// OK
|
||||||
|
int number_small;
|
||||||
|
int number_big;
|
||||||
|
```
|
||||||
|
|
||||||
|
- Enum values are always in upper case and prefixed with the enum name
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
enum llama_vocab_type {
|
||||||
|
LLAMA_VOCAB_TYPE_NONE = 0,
|
||||||
|
LLAMA_VOCAB_TYPE_SPM = 1,
|
||||||
|
LLAMA_VOCAB_TYPE_BPE = 2,
|
||||||
|
LLAMA_VOCAB_TYPE_WPM = 3,
|
||||||
|
LLAMA_VOCAB_TYPE_UGM = 4,
|
||||||
|
LLAMA_VOCAB_TYPE_RWKV = 5,
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
- The general naming pattern is `<class>_<method>`, with `<method>` being `<action>_<noun>`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
llama_model_init(); // class: "llama_model", method: "init"
|
||||||
|
llama_sampler_chain_remove(); // class: "llama_sampler_chain", method: "remove"
|
||||||
|
llama_sampler_get_seed(); // class: "llama_sampler", method: "get_seed"
|
||||||
|
llama_set_embeddings(); // class: "llama_context", method: "set_embeddings"
|
||||||
|
llama_n_threads(); // class: "llama_context", method: "n_threads"
|
||||||
|
llama_adapter_lora_free(); // class: "llama_adapter_lora", method: "free"
|
||||||
|
```
|
||||||
|
|
||||||
|
- The `get` `<action>` can be omitted
|
||||||
|
- The `<noun>` can be omitted if not necessary
|
||||||
|
- The `_context` suffix of the `<class>` is optional. Use it to disambiguate symbols when needed
|
||||||
|
- Use `init`/`free` for constructor/destructor `<action>`
|
||||||
|
|
||||||
|
- Use the `_t` suffix when a type is supposed to be opaque to the user - it's not relevant to them if it is a struct or anything else
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
typedef struct llama_context * llama_context_t;
|
||||||
|
|
||||||
|
enum llama_pooling_type llama_pooling_type(const llama_context_t ctx);
|
||||||
|
```
|
||||||
|
|
||||||
|
_(NOTE: this guideline is yet to be applied to the `whisper.cpp` codebase. New code should follow this guideline)_
|
||||||
|
|
||||||
|
- C/C++ filenames are all lowercase with dashes. Headers use the `.h` extension. Source files use the `.c` or `.cpp` extension
|
||||||
|
- Python filenames are all lowercase with underscores
|
||||||
|
|
||||||
|
- _(TODO: abbreviations usage)_
|
||||||
|
|
||||||
|
# Preprocessor directives
|
||||||
|
|
||||||
|
- _(TODO: add guidelines with examples and apply them to the codebase)_
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#ifdef FOO
|
||||||
|
#endif // FOO
|
||||||
|
```
|
||||||
|
|
||||||
|
# Code maintenance
|
||||||
|
|
||||||
|
- New code should follow the guidelines (coding, naming, etc.) outlined in this document. Exceptions are allowed in isolated, backend-specific parts of the code that do not interface directly with the `ggml` interfaces.
|
||||||
|
_(NOTE: for legacy reasons, existing code is not required to follow this guideline)_
|
||||||
|
|
||||||
|
- For changes in server, please make sure to refer to the [server development documentation](./tools/server/README-dev.md)
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
- Documentation is a community effort
|
||||||
|
- When you need to look into the source code to figure out how to use an API consider adding a short summary to the header file for future reference
|
||||||
|
- When you notice incorrect or outdated documentation, please update it
|
||||||
|
|
||||||
|
# Resources
|
||||||
|
|
||||||
|
The Github issues, PRs and discussions contain a lot of information that can be useful to get familiar with the codebase. For convenience, some of the more important information is referenced from Github projects:
|
||||||
|
|
||||||
|
https://github.com/ggml-org/whisper.cpp/projects
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023-2026 The ggml authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
58
Makefile
Normal file
58
Makefile
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#
|
||||||
|
# Audio samples
|
||||||
|
#
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
cmake -B build $(CMAKE_ARGS)
|
||||||
|
cmake --build build --config Release --parallel $(shell nproc)
|
||||||
|
|
||||||
|
# download a few audio samples into folder "./samples":
|
||||||
|
.PHONY: samples
|
||||||
|
samples:
|
||||||
|
@echo "Downloading samples..."
|
||||||
|
@mkdir -p samples
|
||||||
|
@wget --quiet --show-progress -O samples/gb0.ogg https://upload.wikimedia.org/wikipedia/commons/2/22/George_W._Bush%27s_weekly_radio_address_%28November_1%2C_2008%29.oga
|
||||||
|
@wget --quiet --show-progress -O samples/gb1.ogg https://upload.wikimedia.org/wikipedia/commons/1/1f/George_W_Bush_Columbia_FINAL.ogg
|
||||||
|
@wget --quiet --show-progress -O samples/hp0.ogg https://upload.wikimedia.org/wikipedia/en/d/d4/En.henryfphillips.ogg
|
||||||
|
@wget --quiet --show-progress -O samples/mm1.wav https://cdn.openai.com/whisper/draft-20220913a/micro-machines.wav
|
||||||
|
@wget --quiet --show-progress -O samples/a13.mp3 https://upload.wikimedia.org/wikipedia/commons/transcoded/6/6f/Apollo13-wehaveaproblem.ogg/Apollo13-wehaveaproblem.ogg.mp3
|
||||||
|
@wget --quiet --show-progress -O samples/diffusion2023-07-03.flac https://archive.org/download/diffusion2023-07-03/diffusion2023-07-03.flac
|
||||||
|
|
||||||
|
#
|
||||||
|
# Models
|
||||||
|
#
|
||||||
|
|
||||||
|
# if not already downloaded, the following targets download the specified model and
|
||||||
|
# runs it on all samples in the folder "./samples":
|
||||||
|
|
||||||
|
.PHONY: tiny.en
|
||||||
|
.PHONY: tiny
|
||||||
|
.PHONY: base.en
|
||||||
|
.PHONY: base
|
||||||
|
.PHONY: small.en
|
||||||
|
.PHONY: small
|
||||||
|
.PHONY: medium.en
|
||||||
|
.PHONY: medium
|
||||||
|
.PHONY: large-v1
|
||||||
|
.PHONY: large-v2
|
||||||
|
.PHONY: large-v3
|
||||||
|
.PHONY: large-v3-turbo
|
||||||
|
|
||||||
|
tiny.en tiny base.en base small.en small medium.en medium large-v1 large-v2 large-v3 large-v3-turbo:
|
||||||
|
bash ./models/download-ggml-model.sh $@
|
||||||
|
cmake -B build $(CMAKE_ARGS)
|
||||||
|
cmake --build build --config Release --parallel $(shell nproc)
|
||||||
|
@echo ""
|
||||||
|
@echo "==============================================="
|
||||||
|
@echo "Running $@ on all samples in ./samples ..."
|
||||||
|
@echo "==============================================="
|
||||||
|
@echo ""
|
||||||
|
@for f in samples/*.{flac,mp3,ogg,wav}; do \
|
||||||
|
echo "----------------------------------------------" ; \
|
||||||
|
echo "[+] Running $@ on $$f ... (run 'ffplay $$f' to listen)" ; \
|
||||||
|
echo "----------------------------------------------" ; \
|
||||||
|
echo "" ; \
|
||||||
|
./build/bin/whisper-cli -m models/ggml-$@.bin -f $$f ; \
|
||||||
|
echo "" ; \
|
||||||
|
done
|
||||||
970
README.md
Normal file
970
README.md
Normal file
@@ -0,0 +1,970 @@
|
|||||||
|
# whisper.cpp
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
[](https://opensource.org/licenses/MIT)
|
||||||
|
[](https://github.com/ggml-org/whisper.cpp/releases)
|
||||||
|
[](https://github.com/ggml-org/whisper.cpp/actions)
|
||||||
|
[](https://conan.io/center/whisper-cpp)
|
||||||
|
[](https://www.npmjs.com/package/whisper.cpp/)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
High-performance inference of [OpenAI's Whisper](https://github.com/openai/whisper) automatic speech recognition (ASR) model:
|
||||||
|
|
||||||
|
- Plain C/C++ implementation without dependencies
|
||||||
|
- Apple Silicon first-class citizen - optimized via ARM NEON, Accelerate framework, Metal and [Core ML](#core-ml-support)
|
||||||
|
- AVX intrinsics support for x86 architectures
|
||||||
|
- [VSX intrinsics support for POWER architectures](#power-vsx-intrinsics)
|
||||||
|
- Mixed F16 / F32 precision
|
||||||
|
- [Integer quantization support](#quantization)
|
||||||
|
- Zero memory allocations at runtime
|
||||||
|
- [Vulkan support](#vulkan-gpu-support)
|
||||||
|
- Support for CPU-only inference
|
||||||
|
- [Efficient GPU support for NVIDIA](#nvidia-gpu-support)
|
||||||
|
- [AMD ROCm GPU support](#amd-rocm-gpu-support)
|
||||||
|
- [AMD Ryzen AI NPU Support](#amd-ryzen-ai-npu-support)
|
||||||
|
- [OpenVINO Support](#openvino-support)
|
||||||
|
- [Ascend NPU Support](#ascend-npu-support)
|
||||||
|
- [Moore Threads GPU Support](#moore-threads-gpu-support)
|
||||||
|
- [C-style API](https://github.com/ggml-org/whisper.cpp/blob/master/include/whisper.h)
|
||||||
|
- [Voice Activity Detection (VAD)](#voice-activity-detection-vad)
|
||||||
|
|
||||||
|
Supported platforms:
|
||||||
|
|
||||||
|
- [x] Mac OS (Intel and Arm)
|
||||||
|
- [x] [iOS](examples/whisper.objc)
|
||||||
|
- [x] [Android](examples/whisper.android)
|
||||||
|
- [x] [Java](bindings/java/README.md)
|
||||||
|
- [x] Linux / [FreeBSD](https://github.com/ggml-org/whisper.cpp/issues/56#issuecomment-1350920264)
|
||||||
|
- [x] [WebAssembly](examples/whisper.wasm)
|
||||||
|
- [x] Windows ([MSVC](https://github.com/ggml-org/whisper.cpp/blob/master/.github/workflows/build.yml#L117-L144) and [MinGW](https://github.com/ggml-org/whisper.cpp/issues/168))
|
||||||
|
- [x] [Raspberry Pi](https://github.com/ggml-org/whisper.cpp/discussions/166)
|
||||||
|
- [x] [Docker](https://github.com/ggml-org/whisper.cpp/pkgs/container/whisper.cpp)
|
||||||
|
|
||||||
|
The entire high-level implementation of the model is contained in [whisper.h](include/whisper.h) and [whisper.cpp](src/whisper.cpp).
|
||||||
|
The rest of the code is part of the [`ggml`](https://github.com/ggml-org/ggml) machine learning library.
|
||||||
|
|
||||||
|
Having such a lightweight implementation of the model allows to easily integrate it in different platforms and applications.
|
||||||
|
As an example, here is a video of running the model on an iPhone 13 device - fully offline, on-device: [whisper.objc](examples/whisper.objc)
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/197385372-962a6dea-bca1-4d50-bf96-1d8c27b98c81.mp4
|
||||||
|
|
||||||
|
You can also easily make your own offline voice assistant application: [command](examples/command)
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/204038393-2f846eae-c255-4099-a76d-5735c25c49da.mp4
|
||||||
|
|
||||||
|
On Apple Silicon, the inference runs fully on the GPU via Metal:
|
||||||
|
|
||||||
|
https://github.com/ggml-org/whisper.cpp/assets/1991296/c82e8f86-60dc-49f2-b048-d2fdbd6b5225
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
First clone the repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ggml-org/whisper.cpp.git
|
||||||
|
```
|
||||||
|
|
||||||
|
Navigate into the directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
cd whisper.cpp
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, download one of the Whisper [models](models/README.md) converted in [`ggml` format](#ggml-format). For example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh ./models/download-ggml-model.sh base.en
|
||||||
|
```
|
||||||
|
|
||||||
|
Now build the [whisper-cli](examples/cli) example and transcribe an audio file like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# build the project
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
|
||||||
|
# transcribe an audio file
|
||||||
|
./build/bin/whisper-cli -f samples/jfk.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
For a quick demo, simply run `make base.en`.
|
||||||
|
|
||||||
|
The command downloads the `base.en` model converted to custom `ggml` format and runs the inference on all `.wav` samples in the folder `samples`.
|
||||||
|
|
||||||
|
For detailed usage instructions, run: `./build/bin/whisper-cli -h`
|
||||||
|
|
||||||
|
Note that the [whisper-cli](examples/cli) example currently runs only with 16-bit WAV files, so make sure to convert your input before running the tool.
|
||||||
|
For example, you can use `ffmpeg` like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a pcm_s16le output.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
## More audio samples
|
||||||
|
|
||||||
|
If you want some extra audio samples to play with, simply run:
|
||||||
|
|
||||||
|
```
|
||||||
|
make -j samples
|
||||||
|
```
|
||||||
|
|
||||||
|
This will download a few more audio files from Wikipedia and convert them to 16-bit WAV format via `ffmpeg`.
|
||||||
|
|
||||||
|
You can download and run the other models as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
make -j tiny.en
|
||||||
|
make -j tiny
|
||||||
|
make -j base.en
|
||||||
|
make -j base
|
||||||
|
make -j small.en
|
||||||
|
make -j small
|
||||||
|
make -j medium.en
|
||||||
|
make -j medium
|
||||||
|
make -j large-v1
|
||||||
|
make -j large-v2
|
||||||
|
make -j large-v3
|
||||||
|
make -j large-v3-turbo
|
||||||
|
```
|
||||||
|
|
||||||
|
## Memory usage
|
||||||
|
|
||||||
|
| Model | Disk | Mem |
|
||||||
|
| ------ | ------- | ------- |
|
||||||
|
| tiny | 75 MiB | ~273 MB |
|
||||||
|
| base | 142 MiB | ~388 MB |
|
||||||
|
| small | 466 MiB | ~852 MB |
|
||||||
|
| medium | 1.5 GiB | ~2.1 GB |
|
||||||
|
| large | 2.9 GiB | ~3.9 GB |
|
||||||
|
|
||||||
|
## POWER VSX Intrinsics
|
||||||
|
|
||||||
|
`whisper.cpp` supports POWER architectures and includes code which
|
||||||
|
significantly speeds operation on Linux running on POWER9/10, making it
|
||||||
|
capable of faster-than-realtime transcription on underclocked Raptor
|
||||||
|
Talos II. Ensure you have a BLAS package installed, and replace the
|
||||||
|
standard cmake setup with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# build with GGML_BLAS defined
|
||||||
|
cmake -B build -DGGML_BLAS=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
./build/bin/whisper-cli [ .. etc .. ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quantization
|
||||||
|
|
||||||
|
`whisper.cpp` supports integer quantization of the Whisper `ggml` models.
|
||||||
|
Quantized models require less memory and disk space and depending on the hardware can be processed more efficiently.
|
||||||
|
|
||||||
|
Here are the steps for creating and using a quantized model:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# quantize a model with Q5_0 method
|
||||||
|
cmake -B build
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
./build/bin/quantize models/ggml-base.en.bin models/ggml-base.en-q5_0.bin q5_0
|
||||||
|
|
||||||
|
# run the examples as usual, specifying the quantized model file
|
||||||
|
./build/bin/whisper-cli -m models/ggml-base.en-q5_0.bin ./samples/gb0.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core ML support
|
||||||
|
|
||||||
|
On Apple Silicon devices, the Encoder inference can be executed on the Apple Neural Engine (ANE) via Core ML. This can result in significant
|
||||||
|
speed-up - more than x3 faster compared with CPU-only execution. Here are the instructions for generating a Core ML model and using it with `whisper.cpp`:
|
||||||
|
|
||||||
|
- Install Python dependencies needed for the creation of the Core ML model:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install ane_transformers
|
||||||
|
pip install openai-whisper
|
||||||
|
pip install coremltools
|
||||||
|
```
|
||||||
|
|
||||||
|
- To ensure `coremltools` operates correctly, please confirm that [Xcode](https://developer.apple.com/xcode/) is installed and execute `xcode-select --install` to install the command-line tools.
|
||||||
|
- Python 3.11 is recommended.
|
||||||
|
- MacOS Sonoma (version 14) or newer is recommended, as older versions of MacOS might experience issues with transcription hallucination.
|
||||||
|
- [OPTIONAL] It is recommended to utilize a Python version management system, such as [Miniconda](https://docs.conda.io/en/latest/miniconda.html) for this step:
|
||||||
|
- To create an environment, use: `conda create -n py311-whisper python=3.11 -y`
|
||||||
|
- To activate the environment, use: `conda activate py311-whisper`
|
||||||
|
|
||||||
|
- Generate a Core ML model. For example, to generate a `base.en` model, use:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./models/generate-coreml-model.sh base.en
|
||||||
|
```
|
||||||
|
|
||||||
|
This will generate the folder `models/ggml-base.en-encoder.mlmodelc`
|
||||||
|
|
||||||
|
- Build `whisper.cpp` with Core ML support:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# using CMake
|
||||||
|
cmake -B build -DWHISPER_COREML=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the examples as usual. For example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ ./build/bin/whisper-cli -m models/ggml-base.en.bin -f samples/jfk.wav
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
whisper_init_state: loading Core ML model from 'models/ggml-base.en-encoder.mlmodelc'
|
||||||
|
whisper_init_state: first run on a device may take a while ...
|
||||||
|
whisper_init_state: Core ML model loaded
|
||||||
|
|
||||||
|
system_info: n_threads = 4 / 10 | AVX = 0 | AVX2 = 0 | AVX512 = 0 | FMA = 0 | NEON = 1 | ARM_FMA = 1 | F16C = 0 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 | SSE3 = 0 | VSX = 0 | COREML = 1 |
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
The first run on a device is slow, since the ANE service compiles the Core ML model to some device-specific format.
|
||||||
|
Next runs are faster.
|
||||||
|
|
||||||
|
For more information about the Core ML implementation please refer to PR [#566](https://github.com/ggml-org/whisper.cpp/pull/566).
|
||||||
|
|
||||||
|
## OpenVINO support
|
||||||
|
|
||||||
|
On platforms that support [OpenVINO](https://github.com/openvinotoolkit/openvino), the Encoder inference can be executed
|
||||||
|
on OpenVINO-supported devices including x86 CPUs and Intel GPUs (integrated & discrete).
|
||||||
|
|
||||||
|
This can result in significant speedup in encoder performance. Here are the instructions for generating the OpenVINO model and using it with `whisper.cpp`:
|
||||||
|
|
||||||
|
- First, setup python virtual env. and install python dependencies. Python 3.10 is recommended.
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd models
|
||||||
|
python -m venv openvino_conv_env
|
||||||
|
openvino_conv_env\Scripts\activate
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements-openvino.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Linux and macOS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd models
|
||||||
|
python3 -m venv openvino_conv_env
|
||||||
|
source openvino_conv_env/bin/activate
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install -r requirements-openvino.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
- Generate an OpenVINO encoder model. For example, to generate a `base.en` model, use:
|
||||||
|
|
||||||
|
```
|
||||||
|
python convert-whisper-to-openvino.py --model base.en
|
||||||
|
```
|
||||||
|
|
||||||
|
This will produce ggml-base.en-encoder-openvino.xml/.bin IR model files. It's recommended to relocate these to the same folder as `ggml` models, as that
|
||||||
|
is the default location that the OpenVINO extension will search at runtime.
|
||||||
|
|
||||||
|
- Build `whisper.cpp` with OpenVINO support:
|
||||||
|
|
||||||
|
Download OpenVINO package from [release page](https://github.com/openvinotoolkit/openvino/releases). The recommended version to use is [2026.3.0](https://github.com/openvinotoolkit/openvino/releases/tag/2026.3.0). Ready to use Binaries of the required libraries can be found in the [OpenVino Archives](https://storage.openvinotoolkit.org/repositories/openvino/packages/2026.3/)
|
||||||
|
|
||||||
|
After downloading & extracting package onto your development system, set up required environment by sourcing setupvars script. For example:
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source /path/to/openvino_toolkit_ubuntu/setupvars.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Windows (cmd):
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
C:\Path\To\openvino_toolkit_windows\setupvars.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
And then build the project using cmake:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DWHISPER_OPENVINO=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
- Run the examples as usual. For example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ ./build/bin/whisper-cli -m models/ggml-base.en.bin -f samples/jfk.wav
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
whisper_ctx_init_openvino_encoder: loading OpenVINO model from 'models/ggml-base.en-encoder-openvino.xml'
|
||||||
|
whisper_ctx_init_openvino_encoder: first run on a device may take a while ...
|
||||||
|
whisper_openvino_init: path_model = models/ggml-base.en-encoder-openvino.xml, device = GPU, cache_dir = models/ggml-base.en-encoder-openvino-cache
|
||||||
|
whisper_ctx_init_openvino_encoder: OpenVINO model loaded
|
||||||
|
|
||||||
|
system_info: n_threads = 4 / 8 | AVX = 1 | AVX2 = 1 | AVX512 = 0 | FMA = 1 | NEON = 0 | ARM_FMA = 0 | F16C = 1 | FP16_VA = 0 | WASM_SIMD = 0 | BLAS = 0 | SSE3 = 1 | VSX = 0 | COREML = 0 | OPENVINO = 1 |
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
The first time run on an OpenVINO device is slow, since the OpenVINO framework will compile the IR (Intermediate Representation) model to a device-specific 'blob'. This device-specific blob will get
|
||||||
|
cached for the next run.
|
||||||
|
|
||||||
|
For more information about the OpenVINO implementation please refer to PR [#1037](https://github.com/ggml-org/whisper.cpp/pull/1037).
|
||||||
|
|
||||||
|
## AMD Ryzen™ AI NPU support
|
||||||
|
|
||||||
|
On AMD Ryzen™ AI 300 and 400 Series processors with a dedicated NPU, whisper.cpp can fully offload the Whisper encoder to the NPU via VitisAI, delivering significant speedup over CPU-only inference.
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
Supported Platforms
|
||||||
|
|
||||||
|
- **Windows 11**
|
||||||
|
- **Linux** (Ubuntu 24.04 LTS, Python 3.12)
|
||||||
|
|
||||||
|
Install the XRT runtime and FlexML runtime for your platform:
|
||||||
|
|
||||||
|
- **XRT**: provides the NPU kernel driver and `xrt-smi` diagnostic tool — on Windows this is bundled with the NPU driver; on Linux install it separately following the [NPU driver installation guide](https://ryzenai.docs.amd.com/en/latest/linux.html#install-npu-drivers)
|
||||||
|
- **FlexML runtime** (`flexmlrt`): VitisAI inference engine used by whisper.cpp — download from the [FlexML runtime releases](https://github.com/lemonade-sdk/whisper.cpp-rocm/releases/tag/deps)
|
||||||
|
|
||||||
|
After installing, source the setup scripts in every shell you use to build or run whisper.cpp:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux
|
||||||
|
source /opt/xilinx/xrt/setup.sh
|
||||||
|
source /path/to/flexmlrt/setup.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
:: Windows
|
||||||
|
cd /path/to/flexmlrt && call setup.bat
|
||||||
|
```
|
||||||
|
|
||||||
|
You can verify the NPU is visible with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
xrt-smi examine
|
||||||
|
```
|
||||||
|
|
||||||
|
### Download models
|
||||||
|
|
||||||
|
Download the ggml model and the matching prebuilt VitisAI encoder cache:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux / macOS
|
||||||
|
sh ./models/download-ggml-model.sh base
|
||||||
|
sh ./models/download-vitisai-model.sh base
|
||||||
|
```
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
:: Windows
|
||||||
|
.\models\download-ggml-model.cmd base
|
||||||
|
.\models\download-vitisai-model.cmd base
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the same model name with both scripts. To see all available VitisAI encoder caches:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh ./models/download-vitisai-model.sh --list
|
||||||
|
```
|
||||||
|
|
||||||
|
```cmd
|
||||||
|
.\models\download-vitisai-model.cmd --list
|
||||||
|
```
|
||||||
|
|
||||||
|
The VitisAI script queries the [AMD Ryzen AI Whisper NPU collection on Hugging Face](https://huggingface.co/collections/amd/ryzen-ai-whisper-npu-optimized-onnx-models) and downloads the `.rai` encoder cache as `models/ggml-<model>-encoder-vitisai.rai`.
|
||||||
|
|
||||||
|
> Depending on the `.rai` cache, VitisAI may offload the encoder only, or the encoder plus cross-projection layers. whisper.cpp detects this at runtime and logs the selected offload mode during model initialization.
|
||||||
|
|
||||||
|
### Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DWHISPER_VITISAI=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/whisper-cli -m models/ggml-base.bin -f samples/jfk.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information see the [Ryzen AI documentation](https://ryzenai.docs.amd.com/en/latest/).
|
||||||
|
|
||||||
|
|
||||||
|
## NVIDIA GPU support
|
||||||
|
|
||||||
|
With NVIDIA cards the processing of the models is done efficiently on the GPU via cuBLAS and custom CUDA kernels.
|
||||||
|
First, make sure you have installed `cuda`: https://developer.nvidia.com/cuda-downloads
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with CUDA support:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_CUDA=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
or for newer NVIDIA GPU's (RTX 5000 series):
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_CUDA=1 -DCMAKE_CUDA_ARCHITECTURES="86"
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Vulkan GPU support
|
||||||
|
Cross-vendor solution which allows you to accelerate workload on your GPU.
|
||||||
|
First, make sure your graphics card driver provides support for Vulkan API.
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with Vulkan support:
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_VULKAN=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## AMD ROCm GPU support
|
||||||
|
|
||||||
|
With AMD GPUs the processing can be accelerated via HIP/ROCm.
|
||||||
|
First, make sure you have installed [ROCm](https://rocm.docs.amd.com/en/latest/).
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with HIP support:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_HIP=1 -DAMDGPU_TARGETS="gfx1201"
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace `gfx1201` with your GPU architecture. You can find it with:
|
||||||
|
|
||||||
|
```
|
||||||
|
rocminfo | grep "gfx"
|
||||||
|
```
|
||||||
|
|
||||||
|
Common architectures: `gfx1100` (RX 7900 XTX), `gfx1101` (RX 7800 XT), `gfx1201` (RX 9070 XT).
|
||||||
|
For multiple GPUs with different architectures: `-DAMDGPU_TARGETS="gfx1100;gfx1201"`.
|
||||||
|
|
||||||
|
## BLAS CPU support via OpenBLAS
|
||||||
|
|
||||||
|
Encoder processing can be accelerated on the CPU via OpenBLAS.
|
||||||
|
First, make sure you have installed `openblas`: https://www.openblas.net/
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with OpenBLAS support:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_BLAS=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ascend NPU support
|
||||||
|
|
||||||
|
Ascend NPU provides inference acceleration via [`CANN`](https://www.hiascend.com/en/software/cann) and AI cores.
|
||||||
|
|
||||||
|
First, check if your Ascend NPU device is supported:
|
||||||
|
|
||||||
|
**Verified devices**
|
||||||
|
| Ascend NPU | Status |
|
||||||
|
|:-----------------------------:|:-------:|
|
||||||
|
| Atlas 300T A2 | Support |
|
||||||
|
| Atlas 300I Duo | Support |
|
||||||
|
|
||||||
|
Then, make sure you have installed [`CANN toolkit`](https://www.hiascend.com/en/software/cann/community) . The latest version of CANN is recommended.
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with CANN support:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_CANN=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the inference examples as usual, for example:
|
||||||
|
|
||||||
|
```
|
||||||
|
./build/bin/whisper-cli -f samples/jfk.wav -m models/ggml-base.en.bin -t 8
|
||||||
|
```
|
||||||
|
|
||||||
|
*Notes:*
|
||||||
|
|
||||||
|
- If you have trouble with Ascend NPU device, please create a issue with **[CANN]** prefix/tag.
|
||||||
|
- If you run successfully with your Ascend NPU device, please help update the table `Verified devices`.
|
||||||
|
|
||||||
|
## Moore Threads GPU support
|
||||||
|
|
||||||
|
With Moore Threads cards the processing of the models is done efficiently on the GPU via muBLAS and custom MUSA kernels.
|
||||||
|
First, make sure you have installed `MUSA SDK rc4.2.0`: https://developer.mthreads.com/sdk/download/musa?equipment=&os=&driverVersion=&version=4.2.0
|
||||||
|
|
||||||
|
Now build `whisper.cpp` with MUSA support:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_MUSA=1
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
or specify the architecture for your Moore Threads GPU. For example, if you have a MTT S80 GPU, you can specify the architecture as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -B build -DGGML_MUSA=1 -DMUSA_ARCHITECTURES="21"
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
```
|
||||||
|
|
||||||
|
## FFmpeg support (examples only)
|
||||||
|
|
||||||
|
By default, the examples in this repo use the [miniaudio](https://github.com/mackron/miniaudio) library to decode audio files.
|
||||||
|
Some of the examples also can use FFmpeg for decoding and broader format support. To enable that, build with `WHISPER_COMMON_FFMPEG`.
|
||||||
|
|
||||||
|
First, you need to install required libraries:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Debian/Ubuntu
|
||||||
|
sudo apt install libavcodec-dev libavformat-dev libavutil-dev
|
||||||
|
|
||||||
|
# RHEL/Fedora
|
||||||
|
sudo dnf install libavcodec-free-devel libavformat-free-devel libavutil-free-devel
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can build the project as follows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -D WHISPER_COMMON_FFMPEG=yes
|
||||||
|
cmake --build build
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the following example to confirm it's working:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Convert an audio file to Opus format
|
||||||
|
ffmpeg -i samples/jfk.wav jfk.opus
|
||||||
|
|
||||||
|
# Transcribe the audio file
|
||||||
|
./build/bin/whisper-cli --model models/ggml-base.en.bin --file jfk.opus
|
||||||
|
```
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Docker must be installed and running on your system.
|
||||||
|
- Create a folder to store big models & intermediate files (ex. /whisper/models)
|
||||||
|
|
||||||
|
### Images
|
||||||
|
|
||||||
|
We have multiple Docker images available for this project:
|
||||||
|
|
||||||
|
1. `ghcr.io/ggml-org/whisper.cpp:main`: This image includes the main executable file as well as `curl` and `ffmpeg`. (platforms: `linux/amd64`, `linux/arm64`)
|
||||||
|
2. `ghcr.io/ggml-org/whisper.cpp:main-cuda`: Same as `main` but compiled with CUDA support. (platforms: `linux/amd64`)
|
||||||
|
3. `ghcr.io/ggml-org/whisper.cpp:main-musa`: Same as `main` but compiled with MUSA support. (platforms: `linux/amd64`)
|
||||||
|
4. `ghcr.io/ggml-org/whisper.cpp:main-vulkan`: Same as `main` but compiled with Vulkan support. (platforms: `linux/amd64`)
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# download model and persist it in a local folder
|
||||||
|
docker run -it --rm \
|
||||||
|
-v path/to/models:/models \
|
||||||
|
whisper.cpp:main "./models/download-ggml-model.sh base /models"
|
||||||
|
|
||||||
|
# transcribe an audio file
|
||||||
|
docker run -it --rm \
|
||||||
|
-v path/to/models:/models \
|
||||||
|
-v path/to/audios:/audios \
|
||||||
|
whisper.cpp:main "whisper-cli -m /models/ggml-base.bin -f /audios/jfk.wav"
|
||||||
|
|
||||||
|
# transcribe an audio file in samples folder
|
||||||
|
docker run -it --rm \
|
||||||
|
-v path/to/models:/models \
|
||||||
|
whisper.cpp:main "whisper-cli -m /models/ggml-base.bin -f ./samples/jfk.wav"
|
||||||
|
|
||||||
|
# run the web server
|
||||||
|
docker run -it --rm -p "8080:8080" \
|
||||||
|
-v path/to/models:/models \
|
||||||
|
whisper.cpp:main "whisper-server --host 127.0.0.1 -m /models/ggml-base.bin"
|
||||||
|
|
||||||
|
# run the bench too on the small.en model using 4 threads
|
||||||
|
docker run -it --rm \
|
||||||
|
-v path/to/models:/models \
|
||||||
|
whisper.cpp:main "whisper-bench -m /models/ggml-small.en.bin -t 4"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installing with Conan
|
||||||
|
|
||||||
|
You can install pre-built binaries for whisper.cpp or build it from source using [Conan](https://conan.io/). Use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
conan install --requires="whisper-cpp/[*]" --build=missing
|
||||||
|
```
|
||||||
|
|
||||||
|
For detailed instructions on how to use Conan, please refer to the [Conan documentation](https://docs.conan.io/2/).
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
- Inference only
|
||||||
|
|
||||||
|
## Real-time audio input example
|
||||||
|
|
||||||
|
This is a naive example of performing real-time inference on audio from your microphone.
|
||||||
|
The [stream](examples/stream) tool samples the audio every half a second and runs the transcription continuously.
|
||||||
|
More info is available in [issue #10](https://github.com/ggml-org/whisper.cpp/issues/10).
|
||||||
|
You will need to have [sdl2](https://wiki.libsdl.org/SDL2/Installation) installed for it to work properly.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -B build -DWHISPER_SDL2=ON
|
||||||
|
cmake --build build -j --config Release
|
||||||
|
./build/bin/whisper-stream -m ./models/ggml-base.en.bin -t 8 --step 500 --length 5000
|
||||||
|
```
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/194935793-76afede7-cfa8-48d8-a80f-28ba83be7d09.mp4
|
||||||
|
|
||||||
|
## Confidence color-coding
|
||||||
|
|
||||||
|
Adding the `--print-colors` argument will print the transcribed text using an experimental color coding strategy
|
||||||
|
to highlight words with high or low confidence:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/whisper-cli -m models/ggml-base.en.bin -f samples/gb0.wav --print-colors
|
||||||
|
```
|
||||||
|
|
||||||
|
<img width="965" alt="image" src="https://user-images.githubusercontent.com/1991296/197356445-311c8643-9397-4e5e-b46e-0b4b4daa2530.png">
|
||||||
|
|
||||||
|
## Controlling the length of the generated text segments (experimental)
|
||||||
|
|
||||||
|
For example, to limit the line length to a maximum of 16 characters, simply add `-ml 16`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ ./build/bin/whisper-cli -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 16
|
||||||
|
|
||||||
|
whisper_model_load: loading model from './models/ggml-base.en.bin'
|
||||||
|
...
|
||||||
|
system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 |
|
||||||
|
|
||||||
|
main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ...
|
||||||
|
|
||||||
|
[00:00:00.000 --> 00:00:00.850] And so my
|
||||||
|
[00:00:00.850 --> 00:00:01.590] fellow
|
||||||
|
[00:00:01.590 --> 00:00:04.140] Americans, ask
|
||||||
|
[00:00:04.140 --> 00:00:05.660] not what your
|
||||||
|
[00:00:05.660 --> 00:00:06.840] country can do
|
||||||
|
[00:00:06.840 --> 00:00:08.430] for you, ask
|
||||||
|
[00:00:08.430 --> 00:00:09.440] what you can do
|
||||||
|
[00:00:09.440 --> 00:00:10.020] for your
|
||||||
|
[00:00:10.020 --> 00:00:11.000] country.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Word-level timestamp (experimental)
|
||||||
|
|
||||||
|
The `--max-len` argument can be used to obtain word-level timestamps. Simply use `-ml 1`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
$ ./build/bin/whisper-cli -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -ml 1
|
||||||
|
|
||||||
|
whisper_model_load: loading model from './models/ggml-base.en.bin'
|
||||||
|
...
|
||||||
|
system_info: n_threads = 4 / 10 | AVX2 = 0 | AVX512 = 0 | NEON = 1 | FP16_VA = 1 | WASM_SIMD = 0 | BLAS = 1 |
|
||||||
|
|
||||||
|
main: processing './samples/jfk.wav' (176000 samples, 11.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, timestamps = 1 ...
|
||||||
|
|
||||||
|
[00:00:00.000 --> 00:00:00.320]
|
||||||
|
[00:00:00.320 --> 00:00:00.370] And
|
||||||
|
[00:00:00.370 --> 00:00:00.690] so
|
||||||
|
[00:00:00.690 --> 00:00:00.850] my
|
||||||
|
[00:00:00.850 --> 00:00:01.590] fellow
|
||||||
|
[00:00:01.590 --> 00:00:02.850] Americans
|
||||||
|
[00:00:02.850 --> 00:00:03.300] ,
|
||||||
|
[00:00:03.300 --> 00:00:04.140] ask
|
||||||
|
[00:00:04.140 --> 00:00:04.990] not
|
||||||
|
[00:00:04.990 --> 00:00:05.410] what
|
||||||
|
[00:00:05.410 --> 00:00:05.660] your
|
||||||
|
[00:00:05.660 --> 00:00:06.260] country
|
||||||
|
[00:00:06.260 --> 00:00:06.600] can
|
||||||
|
[00:00:06.600 --> 00:00:06.840] do
|
||||||
|
[00:00:06.840 --> 00:00:07.010] for
|
||||||
|
[00:00:07.010 --> 00:00:08.170] you
|
||||||
|
[00:00:08.170 --> 00:00:08.190] ,
|
||||||
|
[00:00:08.190 --> 00:00:08.430] ask
|
||||||
|
[00:00:08.430 --> 00:00:08.910] what
|
||||||
|
[00:00:08.910 --> 00:00:09.040] you
|
||||||
|
[00:00:09.040 --> 00:00:09.320] can
|
||||||
|
[00:00:09.320 --> 00:00:09.440] do
|
||||||
|
[00:00:09.440 --> 00:00:09.760] for
|
||||||
|
[00:00:09.760 --> 00:00:10.020] your
|
||||||
|
[00:00:10.020 --> 00:00:10.510] country
|
||||||
|
[00:00:10.510 --> 00:00:11.000] .
|
||||||
|
```
|
||||||
|
|
||||||
|
## Speaker segmentation via tinydiarize (experimental)
|
||||||
|
|
||||||
|
More information about this approach is available here: https://github.com/ggml-org/whisper.cpp/pull/1058
|
||||||
|
|
||||||
|
Sample usage:
|
||||||
|
|
||||||
|
```py
|
||||||
|
# download a tinydiarize compatible model
|
||||||
|
./models/download-ggml-model.sh small.en-tdrz
|
||||||
|
|
||||||
|
# run as usual, adding the "-tdrz" command-line argument
|
||||||
|
./build/bin/whisper-cli -f ./samples/a13.wav -m ./models/ggml-small.en-tdrz.bin -tdrz
|
||||||
|
...
|
||||||
|
main: processing './samples/a13.wav' (480000 samples, 30.0 sec), 4 threads, 1 processors, lang = en, task = transcribe, tdrz = 1, timestamps = 1 ...
|
||||||
|
...
|
||||||
|
[00:00:00.000 --> 00:00:03.800] Okay Houston, we've had a problem here. [SPEAKER_TURN]
|
||||||
|
[00:00:03.800 --> 00:00:06.200] This is Houston. Say again please. [SPEAKER_TURN]
|
||||||
|
[00:00:06.200 --> 00:00:08.260] Uh Houston we've had a problem.
|
||||||
|
[00:00:08.260 --> 00:00:11.320] We've had a main beam up on a volt. [SPEAKER_TURN]
|
||||||
|
[00:00:11.320 --> 00:00:13.820] Roger main beam interval. [SPEAKER_TURN]
|
||||||
|
[00:00:13.820 --> 00:00:15.100] Uh uh [SPEAKER_TURN]
|
||||||
|
[00:00:15.100 --> 00:00:18.020] So okay stand, by thirteen we're looking at it. [SPEAKER_TURN]
|
||||||
|
[00:00:18.020 --> 00:00:25.740] Okay uh right now uh Houston the uh voltage is uh is looking good um.
|
||||||
|
[00:00:27.620 --> 00:00:29.940] And we had a a pretty large bank or so.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Karaoke-style movie generation (experimental)
|
||||||
|
|
||||||
|
The [whisper-cli](examples/cli) example provides support for output of karaoke-style movies, where the
|
||||||
|
currently pronounced word is highlighted. Use the `-owts` argument and run the generated bash script.
|
||||||
|
This requires to have `ffmpeg` installed.
|
||||||
|
|
||||||
|
Here are a few _"typical"_ examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/whisper-cli -m ./models/ggml-base.en.bin -f ./samples/jfk.wav -owts
|
||||||
|
source ./samples/jfk.wav.wts
|
||||||
|
ffplay ./samples/jfk.wav.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/199337465-dbee4b5e-9aeb-48a3-b1c6-323ac4db5b2c.mp4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/whisper-cli -m ./models/ggml-base.en.bin -f ./samples/mm0.wav -owts
|
||||||
|
source ./samples/mm0.wav.wts
|
||||||
|
ffplay ./samples/mm0.wav.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/199337504-cc8fd233-0cb7-4920-95f9-4227de3570aa.mp4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/bin/whisper-cli -m ./models/ggml-base.en.bin -f ./samples/gb0.wav -owts
|
||||||
|
source ./samples/gb0.wav.wts
|
||||||
|
ffplay ./samples/gb0.wav.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/199337538-b7b0c7a3-2753-4a88-a0cd-f28a317987ba.mp4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Video comparison of different models
|
||||||
|
|
||||||
|
Use the [scripts/bench-wts.sh](https://github.com/ggml-org/whisper.cpp/blob/master/scripts/bench-wts.sh) script to generate a video in the following format:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/bench-wts.sh samples/jfk.wav
|
||||||
|
ffplay ./samples/jfk.wav.all.mp4
|
||||||
|
```
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/1991296/223206245-2d36d903-cf8e-4f09-8c3b-eb9f9c39d6fc.mp4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benchmarks
|
||||||
|
|
||||||
|
In order to have an objective comparison of the performance of the inference across different system configurations,
|
||||||
|
use the [whisper-bench](examples/bench) tool. The tool simply runs the Encoder part of the model and prints how much time it
|
||||||
|
took to execute it. The results are summarized in the following Github issue:
|
||||||
|
|
||||||
|
[Benchmark results](https://github.com/ggml-org/whisper.cpp/issues/89)
|
||||||
|
|
||||||
|
Additionally a script to run whisper.cpp with different models and audio files is provided [bench.py](scripts/bench.py).
|
||||||
|
|
||||||
|
You can run it with the following command, by default it will run against any standard model in the models folder.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 scripts/bench.py -f samples/jfk.wav -t 2,4,8 -p 1,2
|
||||||
|
```
|
||||||
|
|
||||||
|
It is written in python with the intention of being easy to modify and extend for your benchmarking use case.
|
||||||
|
|
||||||
|
It outputs a csv file with the results of the benchmarking.
|
||||||
|
|
||||||
|
## `ggml` format
|
||||||
|
|
||||||
|
The original models are converted to a custom binary format. This allows to pack everything needed into a single file:
|
||||||
|
|
||||||
|
- model parameters
|
||||||
|
- mel filters
|
||||||
|
- vocabulary
|
||||||
|
- weights
|
||||||
|
|
||||||
|
You can download the converted models using the [models/download-ggml-model.sh](models/download-ggml-model.sh) script
|
||||||
|
or manually from here:
|
||||||
|
|
||||||
|
- https://huggingface.co/ggerganov/whisper.cpp
|
||||||
|
|
||||||
|
For more details, see the conversion script [models/convert-pt-to-ggml.py](models/convert-pt-to-ggml.py) or [models/README.md](models/README.md).
|
||||||
|
|
||||||
|
## [Bindings](https://github.com/ggml-org/whisper.cpp/discussions/categories/bindings)
|
||||||
|
|
||||||
|
- [x] Rust: [tazz4843/whisper-rs](https://github.com/tazz4843/whisper-rs) | [#310](https://github.com/ggml-org/whisper.cpp/discussions/310)
|
||||||
|
- [x] JavaScript: [bindings/javascript](bindings/javascript) | [#309](https://github.com/ggml-org/whisper.cpp/discussions/309)
|
||||||
|
- React Native (iOS / Android): [whisper.rn](https://github.com/mybigday/whisper.rn)
|
||||||
|
- [x] Go: [bindings/go](bindings/go) | [#312](https://github.com/ggml-org/whisper.cpp/discussions/312)
|
||||||
|
- [x] Java:
|
||||||
|
- [GiviMAD/whisper-jni](https://github.com/GiviMAD/whisper-jni)
|
||||||
|
- [x] Ruby: [bindings/ruby](bindings/ruby) | [#507](https://github.com/ggml-org/whisper.cpp/discussions/507)
|
||||||
|
- [x] Objective-C / Swift: [ggml-org/whisper.spm](https://github.com/ggml-org/whisper.spm) | [#313](https://github.com/ggml-org/whisper.cpp/discussions/313)
|
||||||
|
- [exPHAT/SwiftWhisper](https://github.com/exPHAT/SwiftWhisper)
|
||||||
|
- [x] .NET: | [#422](https://github.com/ggml-org/whisper.cpp/discussions/422)
|
||||||
|
- [sandrohanea/whisper.net](https://github.com/sandrohanea/whisper.net)
|
||||||
|
- [NickDarvey/whisper](https://github.com/NickDarvey/whisper)
|
||||||
|
- [x] Python: | [#9](https://github.com/ggml-org/whisper.cpp/issues/9)
|
||||||
|
- [stlukey/whispercpp.py](https://github.com/stlukey/whispercpp.py) (Cython)
|
||||||
|
- [AIWintermuteAI/whispercpp](https://github.com/AIWintermuteAI/whispercpp) (Updated fork of aarnphm/whispercpp)
|
||||||
|
- [aarnphm/whispercpp](https://github.com/aarnphm/whispercpp) (Pybind11)
|
||||||
|
- [abdeladim-s/pywhispercpp](https://github.com/abdeladim-s/pywhispercpp) (Pybind11)
|
||||||
|
- [x] R: [bnosac/audio.whisper](https://github.com/bnosac/audio.whisper)
|
||||||
|
- [x] Unity: [macoron/whisper.unity](https://github.com/Macoron/whisper.unity)
|
||||||
|
|
||||||
|
## XCFramework
|
||||||
|
The XCFramework is a precompiled version of the library for iOS, visionOS, tvOS,
|
||||||
|
and macOS. It can be used in Swift projects without the need to compile the
|
||||||
|
library from source. For example, the v1.7.5 version of the XCFramework can be
|
||||||
|
used as follows:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
// swift-tools-version: 5.10
|
||||||
|
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "Whisper",
|
||||||
|
targets: [
|
||||||
|
.executableTarget(
|
||||||
|
name: "Whisper",
|
||||||
|
dependencies: [
|
||||||
|
"WhisperFramework"
|
||||||
|
]),
|
||||||
|
.binaryTarget(
|
||||||
|
name: "WhisperFramework",
|
||||||
|
url: "https://github.com/ggml-org/whisper.cpp/releases/download/v1.7.5/whisper-v1.7.5-xcframework.zip",
|
||||||
|
checksum: "c7faeb328620d6012e130f3d705c51a6ea6c995605f2df50f6e1ad68c59c6c4a"
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Voice Activity Detection (VAD)
|
||||||
|
Support for Voice Activity Detection (VAD) can be enabled using the `--vad`
|
||||||
|
argument to `whisper-cli`. In addition to this option a VAD model is also
|
||||||
|
required.
|
||||||
|
|
||||||
|
The way this works is that first the audio samples are passed through
|
||||||
|
the VAD model which will detect speech segments. Using this information,
|
||||||
|
only the speech segments that are detected are extracted from the original audio
|
||||||
|
input and passed to whisper for processing. This reduces the amount of audio
|
||||||
|
data that needs to be processed by whisper and can significantly speed up the
|
||||||
|
transcription process.
|
||||||
|
|
||||||
|
The following VAD models are currently supported:
|
||||||
|
|
||||||
|
### Silero-VAD
|
||||||
|
[Silero-vad](https://github.com/snakers4/silero-vad) is a lightweight VAD model
|
||||||
|
written in Python that is fast and accurate.
|
||||||
|
|
||||||
|
Models can be downloaded by running the following command on Linux or MacOS:
|
||||||
|
```console
|
||||||
|
$ ./models/download-vad-model.sh silero-v6.2.0
|
||||||
|
Downloading ggml model silero-v6.2.0 from 'https://huggingface.co/ggml-org/whisper-vad' ...
|
||||||
|
ggml-silero-v6.2.0.bin 100%[==============================================>] 864.35K --.-KB/s in 0.04s
|
||||||
|
Done! Model 'silero-v6.2.0' saved in '/path/models/ggml-silero-v6.2.0.bin'
|
||||||
|
You can now use it like this:
|
||||||
|
|
||||||
|
$ ./build/bin/whisper-cli -vm /path/models/ggml-silero-v6.2.0.bin --vad -f samples/jfk.wav -m models/ggml-base.en.bin
|
||||||
|
|
||||||
|
```
|
||||||
|
And the following command on Windows:
|
||||||
|
```console
|
||||||
|
> .\models\download-vad-model.cmd silero-v6.2.0
|
||||||
|
Downloading vad model silero-v6.2.0...
|
||||||
|
Done! Model silero-v6.2.0 saved in C:\Users\danie\work\ai\whisper.cpp\ggml-silero-v6.2.0.bin
|
||||||
|
You can now use it like this:
|
||||||
|
|
||||||
|
C:\path\build\bin\Release\whisper-cli.exe -vm C:\path\ggml-silero-v6.2.0.bin --vad -m models/ggml-base.en.bin -f samples\jfk.wav
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
To see a list of all available models, run the above commands without any
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
This model can be also be converted manually to ggml using the following command:
|
||||||
|
```console
|
||||||
|
$ python3 -m venv venv && source venv/bin/activate
|
||||||
|
$ (venv) pip install silero-vad
|
||||||
|
$ (venv) $ python models/convert-silero-vad-to-ggml.py --output models/silero.bin
|
||||||
|
Saving GGML Silero-VAD model to models/silero-v6.2.0-ggml.bin
|
||||||
|
```
|
||||||
|
And it can then be used with whisper as follows:
|
||||||
|
```console
|
||||||
|
$ ./build/bin/whisper-cli \
|
||||||
|
--file ./samples/jfk.wav \
|
||||||
|
--model ./models/ggml-base.en.bin \
|
||||||
|
--vad \
|
||||||
|
--vad-model ./models/silero-v6.2.0-ggml.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### VAD Options
|
||||||
|
|
||||||
|
* --vad-threshold: Threshold probability for speech detection. A probability
|
||||||
|
for a speech segment/frame above this threshold will be considered as speech.
|
||||||
|
|
||||||
|
* --vad-min-speech-duration-ms: Minimum speech duration in milliseconds. Speech
|
||||||
|
segments shorter than this value will be discarded to filter out brief noise or
|
||||||
|
false positives.
|
||||||
|
|
||||||
|
* --vad-min-silence-duration-ms: Minimum silence duration in milliseconds. Silence
|
||||||
|
periods must be at least this long to end a speech segment. Shorter silence
|
||||||
|
periods will be ignored and included as part of the speech.
|
||||||
|
|
||||||
|
* --vad-max-speech-duration-s: Maximum speech duration in seconds. Speech segments
|
||||||
|
longer than this will be automatically split into multiple segments at silence
|
||||||
|
points exceeding 98ms to prevent excessively long segments.
|
||||||
|
|
||||||
|
* --vad-speech-pad-ms: Speech padding in milliseconds. Adds this amount of padding
|
||||||
|
before and after each detected speech segment to avoid cutting off speech edges.
|
||||||
|
|
||||||
|
* --vad-samples-overlap: Amount of audio to extend from each speech segment into
|
||||||
|
the next one, in seconds (e.g., 0.10 = 100ms overlap). This ensures speech isn't
|
||||||
|
cut off abruptly between segments when they're concatenated together.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
There are various examples of using the library for different projects in the [examples](examples) folder.
|
||||||
|
Some of the examples are even ported to run in the browser using WebAssembly. Check them out!
|
||||||
|
|
||||||
|
| Example | Web | Description |
|
||||||
|
| --------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
|
| [whisper-cli](examples/cli) | [whisper.wasm](examples/whisper.wasm) | Tool for translating and transcribing audio using Whisper |
|
||||||
|
| [whisper-bench](examples/bench) | [bench.wasm](examples/bench.wasm) | Benchmark the performance of Whisper on your machine |
|
||||||
|
| [whisper-stream](examples/stream) | [stream.wasm](examples/stream.wasm) | Real-time transcription of raw microphone capture |
|
||||||
|
| [whisper-command](examples/command) | [command.wasm](examples/command.wasm) | Basic voice assistant example for receiving voice commands from the mic |
|
||||||
|
| [whisper-server](examples/server) | | HTTP transcription server with OAI-like API |
|
||||||
|
| [whisper-talk-llama](examples/talk-llama) | | Talk with a LLaMA bot |
|
||||||
|
| [whisper.objc](examples/whisper.objc) | | iOS mobile application using whisper.cpp |
|
||||||
|
| [whisper.swiftui](examples/whisper.swiftui) | | SwiftUI iOS / macOS application using whisper.cpp |
|
||||||
|
| [whisper.android](examples/whisper.android) | | Android mobile application using whisper.cpp |
|
||||||
|
| [whisper.nvim](examples/whisper.nvim) | | Speech-to-text plugin for Neovim |
|
||||||
|
| [generate-karaoke.sh](examples/generate-karaoke.sh) | | Helper script to easily [generate a karaoke video](https://youtu.be/uj7hVta4blM) of raw audio capture |
|
||||||
|
| [livestream.sh](examples/livestream.sh) | | [Livestream audio transcription](https://github.com/ggml-org/whisper.cpp/issues/185) |
|
||||||
|
| [yt-wsp.sh](examples/yt-wsp.sh) | | Download + transcribe and/or translate any VOD [(original)](https://gist.github.com/DaniruKun/96f763ec1a037cc92fe1a059b643b818) |
|
||||||
|
| [wchess](examples/wchess) | [wchess.wasm](examples/wchess) | Voice-controlled chess |
|
||||||
|
|
||||||
|
## [Discussions](https://github.com/ggml-org/whisper.cpp/discussions)
|
||||||
|
|
||||||
|
If you have any kind of feedback about this project feel free to use the Discussions section and open a new topic.
|
||||||
|
You can use the [Show and tell](https://github.com/ggml-org/whisper.cpp/discussions/categories/show-and-tell) category
|
||||||
|
to share your own projects that use `whisper.cpp`. If you have a question, make sure to check the
|
||||||
|
[Frequently asked questions (#126)](https://github.com/ggml-org/whisper.cpp/discussions/126) discussion.
|
||||||
249
README_sycl.md
Normal file
249
README_sycl.md
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
# whisper.cpp for SYCL
|
||||||
|
|
||||||
|
[Background](#background)
|
||||||
|
|
||||||
|
[OS](#os)
|
||||||
|
|
||||||
|
[Intel GPU](#intel-gpu)
|
||||||
|
|
||||||
|
[Linux](#linux)
|
||||||
|
|
||||||
|
[Environment Variable](#environment-variable)
|
||||||
|
|
||||||
|
[Known Issue](#known-issue)
|
||||||
|
|
||||||
|
[Todo](#todo)
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
SYCL is a higher-level programming model to improve programming productivity on various hardware accelerators—such as CPUs, GPUs, and FPGAs. It is a single-source embedded domain-specific language based on pure C++17.
|
||||||
|
|
||||||
|
oneAPI is a specification that is open and standards-based, supporting multiple architecture types including but not limited to GPU, CPU, and FPGA. The spec has both direct programming and API-based programming paradigms.
|
||||||
|
|
||||||
|
Intel uses the SYCL as direct programming language to support CPU, GPUs and FPGAs.
|
||||||
|
|
||||||
|
To avoid re-inventing the wheel, this code refers other code paths in llama.cpp (like OpenBLAS, cuBLAS, CLBlast). We use a open-source tool [SYCLomatic](https://github.com/oneapi-src/SYCLomatic) (Commercial release [Intel® DPC++ Compatibility Tool](https://www.intel.com/content/www/us/en/developer/tools/oneapi/dpc-compatibility-tool.html)) migrate to SYCL.
|
||||||
|
|
||||||
|
The whisper.cpp for SYCL is used to support Intel GPUs.
|
||||||
|
|
||||||
|
For Intel CPU, recommend to use whisper.cpp for X86 (Intel MKL build).
|
||||||
|
|
||||||
|
## OS
|
||||||
|
|
||||||
|
|OS|Status|Verified|
|
||||||
|
|-|-|-|
|
||||||
|
|Linux|Support|Ubuntu 22.04|
|
||||||
|
|Windows|Ongoing| |
|
||||||
|
|
||||||
|
|
||||||
|
## Intel GPU
|
||||||
|
|
||||||
|
|Intel GPU| Status | Verified Model|
|
||||||
|
|-|-|-|
|
||||||
|
|Intel Data Center Max Series| Support| Max 1550|
|
||||||
|
|Intel Data Center Flex Series| Support| Flex 170|
|
||||||
|
|Intel Arc Series| Support| Arc 770|
|
||||||
|
|Intel built-in Arc GPU| Support| built-in Arc GPU in Meteor Lake|
|
||||||
|
|Intel iGPU| Support| iGPU in i5-1250P, i7-1165G7|
|
||||||
|
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
### Setup Environment
|
||||||
|
|
||||||
|
1. Install Intel GPU driver.
|
||||||
|
|
||||||
|
a. Please install Intel GPU driver by official guide: [Install GPU Drivers](https://dgpu-docs.intel.com/driver/installation.html).
|
||||||
|
|
||||||
|
Note: for iGPU, please install the client GPU driver.
|
||||||
|
|
||||||
|
b. Add user to group: video, render.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo usermod -aG render username
|
||||||
|
sudo usermod -aG video username
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: re-login to enable it.
|
||||||
|
|
||||||
|
c. Check
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo apt install clinfo
|
||||||
|
sudo clinfo -l
|
||||||
|
```
|
||||||
|
|
||||||
|
Output (example):
|
||||||
|
|
||||||
|
```
|
||||||
|
Platform #0: Intel(R) OpenCL Graphics
|
||||||
|
`-- Device #0: Intel(R) Arc(TM) A770 Graphics
|
||||||
|
|
||||||
|
|
||||||
|
Platform #0: Intel(R) OpenCL HD Graphics
|
||||||
|
`-- Device #0: Intel(R) Iris(R) Xe Graphics [0x9a49]
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install Intel® oneAPI Base toolkit.
|
||||||
|
|
||||||
|
|
||||||
|
a. Please follow the procedure in [Get the Intel® oneAPI Base Toolkit ](https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit.html).
|
||||||
|
|
||||||
|
Recommend to install to default folder: **/opt/intel/oneapi**.
|
||||||
|
|
||||||
|
Following guide use the default folder as example. If you use other folder, please modify the following guide info with your folder.
|
||||||
|
|
||||||
|
b. Check
|
||||||
|
|
||||||
|
```
|
||||||
|
source /opt/intel/oneapi/setvars.sh
|
||||||
|
|
||||||
|
sycl-ls
|
||||||
|
```
|
||||||
|
|
||||||
|
There should be one or more level-zero devices. Like **[ext_oneapi_level_zero:gpu:0]**.
|
||||||
|
|
||||||
|
Output (example):
|
||||||
|
```
|
||||||
|
[opencl:acc:0] Intel(R) FPGA Emulation Platform for OpenCL(TM), Intel(R) FPGA Emulation Device OpenCL 1.2 [2023.16.10.0.17_160000]
|
||||||
|
[opencl:cpu:1] Intel(R) OpenCL, 13th Gen Intel(R) Core(TM) i7-13700K OpenCL 3.0 (Build 0) [2023.16.10.0.17_160000]
|
||||||
|
[opencl:gpu:2] Intel(R) OpenCL Graphics, Intel(R) Arc(TM) A770 Graphics OpenCL 3.0 NEO [23.30.26918.50]
|
||||||
|
[ext_oneapi_level_zero:gpu:0] Intel(R) Level-Zero, Intel(R) Arc(TM) A770 Graphics 1.3 [1.3.26918]
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build locally:
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
source /opt/intel/oneapi/setvars.sh
|
||||||
|
|
||||||
|
#for FP16
|
||||||
|
#cmake .. -DWHISPER_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DWHISPER_SYCL_F16=ON
|
||||||
|
|
||||||
|
#for FP32
|
||||||
|
cmake .. -DWHISPER_SYCL=ON -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx
|
||||||
|
|
||||||
|
#build example/main only
|
||||||
|
#cmake --build . --config Release --target main
|
||||||
|
|
||||||
|
#build all binary
|
||||||
|
cmake --build . --config Release -v
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```
|
||||||
|
./examples/sycl/build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Note:
|
||||||
|
|
||||||
|
- By default, it will build for all binary files. It will take more time. To reduce the time, we recommend to build for **example/main** only.
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
1. Put model file to folder **models**
|
||||||
|
|
||||||
|
2. Enable oneAPI running environment
|
||||||
|
|
||||||
|
```
|
||||||
|
source /opt/intel/oneapi/setvars.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
3. List device ID
|
||||||
|
|
||||||
|
Run without parameter:
|
||||||
|
|
||||||
|
```
|
||||||
|
./build/bin/ls-sycl-device
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
./build/bin/main
|
||||||
|
```
|
||||||
|
|
||||||
|
Check the ID in startup log, like:
|
||||||
|
|
||||||
|
```
|
||||||
|
found 4 SYCL devices:
|
||||||
|
Device 0: Intel(R) Arc(TM) A770 Graphics, compute capability 1.3,
|
||||||
|
max compute_units 512, max work group size 1024, max sub group size 32, global mem size 16225243136
|
||||||
|
Device 1: Intel(R) FPGA Emulation Device, compute capability 1.2,
|
||||||
|
max compute_units 24, max work group size 67108864, max sub group size 64, global mem size 67065057280
|
||||||
|
Device 2: 13th Gen Intel(R) Core(TM) i7-13700K, compute capability 3.0,
|
||||||
|
max compute_units 24, max work group size 8192, max sub group size 64, global mem size 67065057280
|
||||||
|
Device 3: Intel(R) Arc(TM) A770 Graphics, compute capability 3.0,
|
||||||
|
max compute_units 512, max work group size 1024, max sub group size 32, global mem size 16225243136
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|Attribute|Note|
|
||||||
|
|-|-|
|
||||||
|
|compute capability 1.3|Level-zero running time, recommended |
|
||||||
|
|compute capability 3.0|OpenCL running time, slower than level-zero in most cases|
|
||||||
|
|
||||||
|
4. Set device ID and execute whisper.cpp
|
||||||
|
|
||||||
|
Set device ID = 0 by **GGML_SYCL_DEVICE=0**
|
||||||
|
|
||||||
|
```
|
||||||
|
GGML_SYCL_DEVICE=0 ./build/bin/main -m models/ggml-base.en.bin -f samples/jfk.wav
|
||||||
|
```
|
||||||
|
or run by script:
|
||||||
|
|
||||||
|
```
|
||||||
|
./examples/sycl/run_whisper.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
5. Check the device ID in output
|
||||||
|
|
||||||
|
Like:
|
||||||
|
```
|
||||||
|
Using device **0** (Intel(R) Arc(TM) A770 Graphics) as main device
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Environment Variable
|
||||||
|
|
||||||
|
#### Build
|
||||||
|
|
||||||
|
|Name|Value|Function|
|
||||||
|
|-|-|-|
|
||||||
|
|WHISPER_SYCL|ON (mandatory)|Enable build with SYCL code path. <br>For FP32/FP16, WHISPER_SYCL=ON is mandatory.|
|
||||||
|
|WHISPER_SYCL_F16|ON (optional)|Enable FP16 build with SYCL code path.For FP32, do not set it.|
|
||||||
|
|CMAKE_C_COMPILER|icx|Use icx compiler for SYCL code path|
|
||||||
|
|CMAKE_CXX_COMPILER|icpx|use icpx for SYCL code path|
|
||||||
|
|
||||||
|
#### Running
|
||||||
|
|
||||||
|
|
||||||
|
|Name|Value|Function|
|
||||||
|
|-|-|-|
|
||||||
|
|GGML_SYCL_DEVICE|0 (default) or 1|Set the device id used. Check the device ids by default running output|
|
||||||
|
|GGML_SYCL_DEBUG|0 (default) or 1|Enable log function by macro: GGML_SYCL_DEBUG|
|
||||||
|
|
||||||
|
## Known Issue
|
||||||
|
|
||||||
|
- Error: `error while loading shared libraries: libsycl.so.7: cannot open shared object file: No such file or directory`.
|
||||||
|
|
||||||
|
Miss to enable oneAPI running environment.
|
||||||
|
|
||||||
|
Install oneAPI base toolkit and enable it by: `source /opt/intel/oneapi/setvars.sh`.
|
||||||
|
|
||||||
|
|
||||||
|
- Hang during startup
|
||||||
|
|
||||||
|
llama.cpp use mmap as default way to read model file and copy to GPU. In some system, memcpy will be abnormal and block.
|
||||||
|
|
||||||
|
Solution: add **--no-mmap**.
|
||||||
|
|
||||||
|
## Todo
|
||||||
|
|
||||||
|
- Support to build in Windows.
|
||||||
|
|
||||||
|
- Support multiple cards.
|
||||||
19
bindings/CMakeLists.txt
Normal file
19
bindings/CMakeLists.txt
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
if (EMSCRIPTEN)
|
||||||
|
add_subdirectory(javascript)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/javascript/publish.log
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/whisper.js
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/libwhisper.worker.js
|
||||||
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/javascript/package.json
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/javascript
|
||||||
|
COMMAND npm publish
|
||||||
|
COMMAND touch publish.log
|
||||||
|
COMMENT "Publishing npm module v${PROJECT_VERSION}"
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(publish-npm
|
||||||
|
DEPENDS javascript/publish.log
|
||||||
|
)
|
||||||
|
endif()
|
||||||
2
bindings/go/.gitignore
vendored
Normal file
2
bindings/go/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
models
|
||||||
21
bindings/go/LICENSE
Normal file
21
bindings/go/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 David Thorpe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
72
bindings/go/Makefile
Normal file
72
bindings/go/Makefile
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
ifndef UNAME_S
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef UNAME_P
|
||||||
|
UNAME_P := $(shell uname -p)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef UNAME_M
|
||||||
|
UNAME_M := $(shell uname -m)
|
||||||
|
endif
|
||||||
|
|
||||||
|
GGML_METAL_PATH_RESOURCES := $(abspath ../..)
|
||||||
|
BUILD_DIR := build_go
|
||||||
|
MODELS_DIR := models
|
||||||
|
EXAMPLES_DIR := $(wildcard examples/*)
|
||||||
|
INCLUDE_PATH := $(abspath ../../include):$(abspath ../../ggml/include)
|
||||||
|
LIBRARY_PATH := $(abspath ../../${BUILD_DIR}/src):$(abspath ../../${BUILD_DIR}/ggml/src)
|
||||||
|
|
||||||
|
ifeq ($(GGML_CUDA),1)
|
||||||
|
LIBRARY_PATH := $(LIBRARY_PATH):$(CUDA_PATH)/targets/$(UNAME_M)-linux/lib/
|
||||||
|
BUILD_FLAGS := -ldflags "-extldflags '-lcudart -lcuda -lcublas'"
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
LIBRARY_PATH := $(LIBRARY_PATH):$(abspath ../../${BUILD_DIR}/ggml/src/ggml-blas):$(abspath ../../${BUILD_DIR}/ggml/src/ggml-metal)
|
||||||
|
EXT_LDFLAGS := -framework Foundation -framework Metal -framework MetalKit -lggml-metal -lggml-blas
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: clean whisper examples
|
||||||
|
|
||||||
|
whisper: mkdir
|
||||||
|
cmake -S ../.. -B ../../${BUILD_DIR} \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_SHARED_LIBS=OFF
|
||||||
|
cmake --build ../../${BUILD_DIR} --target whisper
|
||||||
|
|
||||||
|
test: model-small whisper modtidy
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v .
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go test -ldflags "-extldflags '$(EXT_LDFLAGS)'" -v ./pkg/whisper/...
|
||||||
|
else
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v .
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go test -v ./pkg/whisper/...
|
||||||
|
endif
|
||||||
|
|
||||||
|
examples: $(EXAMPLES_DIR)
|
||||||
|
|
||||||
|
model-small: mkdir examples/go-model-download
|
||||||
|
@${BUILD_DIR}/go-model-download -out models ggml-small.en.bin
|
||||||
|
|
||||||
|
$(EXAMPLES_DIR): mkdir whisper modtidy
|
||||||
|
@echo Build example $(notdir $@)
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} GGML_METAL_PATH_RESOURCES=${GGML_METAL_PATH_RESOURCES} go build ${BUILD_FLAGS} -ldflags "-extldflags '$(EXT_LDFLAGS)'" -o ${BUILD_DIR}/$(notdir $@) ./$@
|
||||||
|
else
|
||||||
|
@C_INCLUDE_PATH=${INCLUDE_PATH} LIBRARY_PATH=${LIBRARY_PATH} go build ${BUILD_FLAGS} -o ${BUILD_DIR}/$(notdir $@) ./$@
|
||||||
|
endif
|
||||||
|
|
||||||
|
mkdir:
|
||||||
|
@echo Mkdir ${BUILD_DIR}
|
||||||
|
@install -d ${BUILD_DIR}
|
||||||
|
@echo Mkdir ${MODELS_DIR}
|
||||||
|
@install -d ${MODELS_DIR}
|
||||||
|
|
||||||
|
modtidy:
|
||||||
|
@go mod tidy
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo Clean
|
||||||
|
@rm -fr $(BUILD_DIR)
|
||||||
|
@go clean
|
||||||
106
bindings/go/README.md
Normal file
106
bindings/go/README.md
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# Go bindings for Whisper
|
||||||
|
|
||||||
|
This package provides Go bindings for whisper.cpp. They have been tested on:
|
||||||
|
|
||||||
|
* Darwin (OS X) 12.6 on x64_64
|
||||||
|
* Debian Linux on arm64
|
||||||
|
* Fedora Linux on x86_64
|
||||||
|
|
||||||
|
The "low level" bindings are in the `bindings/go` directory and there is a more
|
||||||
|
Go-style package in the `bindings/go/pkg/whisper` directory. The most simple usage
|
||||||
|
is as follows:
|
||||||
|
|
||||||
|
```go
|
||||||
|
import (
|
||||||
|
"github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var modelpath string // Path to the model
|
||||||
|
var samples []float32 // Samples to process
|
||||||
|
|
||||||
|
// Load the model
|
||||||
|
model, err := whisper.New(modelpath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
// Process samples
|
||||||
|
context, err := model.NewContext()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := context.Process(samples, nil, nil, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print out the results
|
||||||
|
for {
|
||||||
|
segment, err := context.NextSegment()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("[%6s->%6s] %s\n", segment.Start, segment.End, segment.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building & Testing
|
||||||
|
|
||||||
|
In order to build, you need to have the Go compiler installed. You can get it from [here](https://golang.org/dl/). Run the tests with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ggml-org/whisper.cpp.git
|
||||||
|
cd whisper.cpp/bindings/go
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
This will compile a static `libwhisper.a` in a `build` folder, download a model file, then run the tests. To build the examples:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make examples
|
||||||
|
```
|
||||||
|
|
||||||
|
To build using cuda support add `GGML_CUDA=1`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GGML_CUDA=1 make examples
|
||||||
|
```
|
||||||
|
|
||||||
|
The examples are placed in the `build` directory. Once built, you can download all the models with the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/go-model-download -out models
|
||||||
|
```
|
||||||
|
|
||||||
|
And you can then test a model against samples with the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./build/go-whisper -model models/ggml-tiny.en.bin samples/jfk.wav
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using the bindings
|
||||||
|
|
||||||
|
To use the bindings in your own software,
|
||||||
|
|
||||||
|
1. Import `github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper` (or `github.com/ggerganov/whisper.cpp/bindings/go` into your package;
|
||||||
|
2. Compile `libwhisper.a` (you can use `make whisper` in the `bindings/go` directory);
|
||||||
|
3. Link your go binary against whisper by setting the environment variables `C_INCLUDE_PATH` and `LIBRARY_PATH`
|
||||||
|
to point to the `whisper.h` file directory and `libwhisper.a` file directory respectively.
|
||||||
|
|
||||||
|
Look at the `Makefile` in the `bindings/go` directory for an example.
|
||||||
|
|
||||||
|
The API Documentation:
|
||||||
|
|
||||||
|
* https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go
|
||||||
|
* https://pkg.go.dev/github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper
|
||||||
|
|
||||||
|
Getting help:
|
||||||
|
|
||||||
|
* Follow the discussion for the go bindings [here](https://github.com/ggml-org/whisper.cpp/discussions/312)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The license for the Go bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details.
|
||||||
|
|
||||||
5
bindings/go/doc.go
Normal file
5
bindings/go/doc.go
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
github.com/ggml-org/whisper.cpp/bindings/go
|
||||||
|
provides a speech-to-text service bindings for the Go programming language.
|
||||||
|
*/
|
||||||
|
package whisper
|
||||||
31
bindings/go/examples/go-model-download/context.go
Normal file
31
bindings/go/examples/go-model-download/context.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ContextForSignal returns a context object which is cancelled when a signal
|
||||||
|
// is received. It returns nil if no signal parameter is provided
|
||||||
|
func ContextForSignal(signals ...os.Signal) context.Context {
|
||||||
|
if len(signals) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ch := make(chan os.Signal, 1) // Buffered channel with space for 1 signal
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
|
// Send message on channel when signal received
|
||||||
|
signal.Notify(ch, signals...)
|
||||||
|
|
||||||
|
// When any signal is received, call cancel
|
||||||
|
go func() {
|
||||||
|
<-ch
|
||||||
|
cancel()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
311
bindings/go/examples/go-model-download/main.go
Normal file
311
bindings/go/examples/go-model-download/main.go
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CONSTANTS
|
||||||
|
|
||||||
|
const (
|
||||||
|
srcUrl = "https://huggingface.co/ggerganov/whisper.cpp/resolve/main/" // The location of the models
|
||||||
|
srcExt = ".bin" // Filename extension
|
||||||
|
bufSize = 1024 * 64 // Size of the buffer used for downloading the model
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// The models which will be downloaded, if no model is specified as an argument
|
||||||
|
modelNames = []string{
|
||||||
|
"tiny", "tiny-q5_1", "tiny-q8_0",
|
||||||
|
"tiny.en", "tiny.en-q5_1", "tiny.en-q8_0",
|
||||||
|
"base", "base-q5_1", "base-q8_0",
|
||||||
|
"base.en", "base.en-q5_1", "base.en-q8_0",
|
||||||
|
"small", "small-q5_1", "small-q8_0",
|
||||||
|
"small.en", "small.en-q5_1", "small.en-q8_0",
|
||||||
|
"medium", "medium-q5_0", "medium-q8_0",
|
||||||
|
"medium.en", "medium.en-q5_0", "medium.en-q8_0",
|
||||||
|
"large-v1",
|
||||||
|
"large-v2", "large-v2-q5_0", "large-v2-q8_0",
|
||||||
|
"large-v3", "large-v3-q5_0",
|
||||||
|
"large-v3-turbo", "large-v3-turbo-q5_0", "large-v3-turbo-q8_0",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// The output folder. When not set, use current working directory.
|
||||||
|
flagOut = flag.String("out", "", "Output folder")
|
||||||
|
|
||||||
|
// HTTP timeout parameter - will timeout if takes longer than this to download a model
|
||||||
|
flagTimeout = flag.Duration("timeout", 30*time.Minute, "HTTP timeout")
|
||||||
|
|
||||||
|
// Quiet parameter - will not print progress if set
|
||||||
|
flagQuiet = flag.Bool("quiet", false, "Quiet mode")
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MAIN
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Usage = func() {
|
||||||
|
name := filepath.Base(flag.CommandLine.Name())
|
||||||
|
fmt.Fprintf(flag.CommandLine.Output(), `
|
||||||
|
Usage: %s [options] [<model>...]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-out string Specify the output folder where models will be saved.
|
||||||
|
Default: Current working directory.
|
||||||
|
-timeout duration Set the maximum duration for downloading a model.
|
||||||
|
Example: 10m, 1h (default: 30m0s).
|
||||||
|
-quiet Suppress all output except errors.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
1. Download a specific model:
|
||||||
|
%s -out ./models tiny-q8_0
|
||||||
|
|
||||||
|
2. Download all models:
|
||||||
|
%s -out ./models
|
||||||
|
|
||||||
|
`, name, name, name)
|
||||||
|
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// Get output path
|
||||||
|
out, err := GetOut()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error:", err)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create context which quits on SIGINT or SIGQUIT
|
||||||
|
ctx := ContextForSignal(os.Interrupt, syscall.SIGQUIT)
|
||||||
|
|
||||||
|
// Progress filehandle
|
||||||
|
progress := os.Stdout
|
||||||
|
if *flagQuiet {
|
||||||
|
progress, err = os.Open(os.DevNull)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error:", err)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
defer progress.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download models - exit on error or interrupt
|
||||||
|
for _, model := range GetModels() {
|
||||||
|
url, err := URLForModel(model)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "Error:", err)
|
||||||
|
continue
|
||||||
|
} else if path, err := Download(ctx, progress, url, out); err == nil || err == io.EOF {
|
||||||
|
continue
|
||||||
|
} else if err == context.Canceled {
|
||||||
|
os.Remove(path)
|
||||||
|
fmt.Fprintln(progress, "\nInterrupted")
|
||||||
|
break
|
||||||
|
} else if err == context.DeadlineExceeded {
|
||||||
|
os.Remove(path)
|
||||||
|
fmt.Fprintln(progress, "Timeout downloading model")
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
os.Remove(path)
|
||||||
|
fmt.Fprintln(os.Stderr, "Error:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
// GetOut returns the path to the output directory
|
||||||
|
func GetOut() (string, error) {
|
||||||
|
if *flagOut == "" {
|
||||||
|
return os.Getwd()
|
||||||
|
}
|
||||||
|
if info, err := os.Stat(*flagOut); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if !info.IsDir() {
|
||||||
|
return "", fmt.Errorf("not a directory: %s", info.Name())
|
||||||
|
} else {
|
||||||
|
return *flagOut, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetModels returns the list of models to download
|
||||||
|
func GetModels() []string {
|
||||||
|
if flag.NArg() == 0 {
|
||||||
|
fmt.Println("No model specified.")
|
||||||
|
fmt.Println("Preparing to download all models...")
|
||||||
|
|
||||||
|
// Calculate total download size
|
||||||
|
fmt.Println("Calculating total download size...")
|
||||||
|
totalSize, err := CalculateTotalDownloadSize(modelNames)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error calculating download sizes:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("View available models: https://huggingface.co/ggerganov/whisper.cpp/tree/main")
|
||||||
|
fmt.Printf("Total download size: %.2f GB\n", float64(totalSize)/(1024*1024*1024))
|
||||||
|
fmt.Println("Would you like to download all models? (y/N)")
|
||||||
|
|
||||||
|
// Prompt for user input
|
||||||
|
var response string
|
||||||
|
fmt.Scanln(&response)
|
||||||
|
if response != "y" && response != "Y" {
|
||||||
|
fmt.Println("Aborting. Specify a model to download.")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
return modelNames // Return all models if confirmed
|
||||||
|
}
|
||||||
|
return flag.Args() // Return specific models if arguments are provided
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalculateTotalDownloadSize(models []string) (int64, error) {
|
||||||
|
var totalSize int64
|
||||||
|
client := http.Client{}
|
||||||
|
|
||||||
|
for _, model := range models {
|
||||||
|
modelURL, err := URLForModel(model)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue a HEAD request to get the file size
|
||||||
|
req, err := http.NewRequest("HEAD", modelURL, nil)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
fmt.Printf("Warning: Unable to fetch size for %s (HTTP %d)\n", model, resp.StatusCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
size := resp.ContentLength
|
||||||
|
totalSize += size
|
||||||
|
}
|
||||||
|
return totalSize, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// URLForModel returns the URL for the given model on huggingface.co
|
||||||
|
func URLForModel(model string) (string, error) {
|
||||||
|
// Ensure "ggml-" prefix is added only once
|
||||||
|
if !strings.HasPrefix(model, "ggml-") {
|
||||||
|
model = "ggml-" + model
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure ".bin" extension is added only once
|
||||||
|
if filepath.Ext(model) != srcExt {
|
||||||
|
model += srcExt
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the base URL
|
||||||
|
url, err := url.Parse(srcUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure no trailing slash in the base URL
|
||||||
|
url.Path = fmt.Sprintf("%s/%s", strings.TrimSuffix(url.Path, "/"), model)
|
||||||
|
return url.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download downloads the model from the given URL to the given output directory
|
||||||
|
func Download(ctx context.Context, p io.Writer, model, out string) (string, error) {
|
||||||
|
// Create HTTP client
|
||||||
|
client := http.Client{
|
||||||
|
Timeout: *flagTimeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate the download
|
||||||
|
req, err := http.NewRequest("GET", model, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return "", fmt.Errorf("%s: %s", model, resp.Status)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If output file exists and is the same size as the model, skip
|
||||||
|
path := filepath.Join(out, filepath.Base(model))
|
||||||
|
if info, err := os.Stat(path); err == nil && info.Size() == resp.ContentLength {
|
||||||
|
fmt.Fprintln(p, "Skipping", model, "as it already exists")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create file
|
||||||
|
w, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
// Report
|
||||||
|
fmt.Fprintln(p, "Downloading", model, "to", out)
|
||||||
|
|
||||||
|
// Progressively download the model
|
||||||
|
data := make([]byte, bufSize)
|
||||||
|
count, pct := int64(0), int64(0)
|
||||||
|
ticker := time.NewTicker(5 * time.Second)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
// Cancelled, return error
|
||||||
|
return path, ctx.Err()
|
||||||
|
case <-ticker.C:
|
||||||
|
pct = DownloadReport(p, pct, count, resp.ContentLength)
|
||||||
|
default:
|
||||||
|
// Read body
|
||||||
|
n, err := resp.Body.Read(data)
|
||||||
|
if n > 0 {
|
||||||
|
if m, err := w.Write(data[:n]); err != nil {
|
||||||
|
return path, err
|
||||||
|
} else {
|
||||||
|
count += int64(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if err == io.EOF {
|
||||||
|
DownloadReport(p, pct, count, resp.ContentLength)
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
return path, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report periodically reports the download progress when percentage changes
|
||||||
|
func DownloadReport(w io.Writer, pct, count, total int64) int64 {
|
||||||
|
pct_ := count * 100 / total
|
||||||
|
if pct_ > pct {
|
||||||
|
fmt.Fprintf(w, " ...%d MB written (%d%%)\n", count/1e6, pct_)
|
||||||
|
}
|
||||||
|
return pct_
|
||||||
|
}
|
||||||
22
bindings/go/examples/go-whisper/color.go
Normal file
22
bindings/go/examples/go-whisper/color.go
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CONSTANTS
|
||||||
|
|
||||||
|
const (
|
||||||
|
Reset = "\033[0m"
|
||||||
|
RGBPrefix = "\033[38;5;" // followed by RGB values in decimal format separated by colons
|
||||||
|
RGBSuffix = "m"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
// Colorize text with RGB values, from 0 to 23
|
||||||
|
func Colorize(text string, v int) string {
|
||||||
|
// https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit
|
||||||
|
// Grayscale colors are in the range 232-255
|
||||||
|
return RGBPrefix + fmt.Sprint(v%24+232) + RGBSuffix + text + Reset
|
||||||
|
}
|
||||||
147
bindings/go/examples/go-whisper/flags.go
Normal file
147
bindings/go/examples/go-whisper/flags.go
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// Packages
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TYPES
|
||||||
|
|
||||||
|
type Flags struct {
|
||||||
|
*flag.FlagSet
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LIFECYCLE
|
||||||
|
|
||||||
|
func NewFlags(name string, args []string) (*Flags, error) {
|
||||||
|
flags := &Flags{
|
||||||
|
FlagSet: flag.NewFlagSet(name, flag.ContinueOnError),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register the command line arguments
|
||||||
|
registerFlags(flags)
|
||||||
|
|
||||||
|
// Parse command line
|
||||||
|
if err := flags.Parse(args); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return flags, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
func (flags *Flags) GetModel() string {
|
||||||
|
return flags.Lookup("model").Value.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetLanguage() string {
|
||||||
|
return flags.Lookup("language").Value.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) IsTranslate() bool {
|
||||||
|
return flags.Lookup("translate").Value.(flag.Getter).Get().(bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetOffset() time.Duration {
|
||||||
|
return flags.Lookup("offset").Value.(flag.Getter).Get().(time.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetDuration() time.Duration {
|
||||||
|
return flags.Lookup("duration").Value.(flag.Getter).Get().(time.Duration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetThreads() uint {
|
||||||
|
return flags.Lookup("threads").Value.(flag.Getter).Get().(uint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetOut() string {
|
||||||
|
return strings.ToLower(flags.Lookup("out").Value.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) IsTokens() bool {
|
||||||
|
return flags.Lookup("tokens").Value.String() == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) IsColorize() bool {
|
||||||
|
return flags.Lookup("colorize").Value.String() == "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetMaxLen() uint {
|
||||||
|
return flags.Lookup("max-len").Value.(flag.Getter).Get().(uint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetMaxTokens() uint {
|
||||||
|
return flags.Lookup("max-tokens").Value.(flag.Getter).Get().(uint)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) GetWordThreshold() float32 {
|
||||||
|
return float32(flags.Lookup("word-thold").Value.(flag.Getter).Get().(float64))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *Flags) SetParams(context whisper.Context) error {
|
||||||
|
if lang := flags.GetLanguage(); lang != "" && lang != "auto" {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting language to %q\n", lang)
|
||||||
|
if err := context.SetLanguage(lang); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flags.IsTranslate() && context.IsMultilingual() {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting translate to true\n")
|
||||||
|
context.SetTranslate(true)
|
||||||
|
}
|
||||||
|
if offset := flags.GetOffset(); offset != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting offset to %v\n", offset)
|
||||||
|
context.SetOffset(offset)
|
||||||
|
}
|
||||||
|
if duration := flags.GetDuration(); duration != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting duration to %v\n", duration)
|
||||||
|
context.SetDuration(duration)
|
||||||
|
}
|
||||||
|
if threads := flags.GetThreads(); threads != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting threads to %d\n", threads)
|
||||||
|
context.SetThreads(threads)
|
||||||
|
}
|
||||||
|
if max_len := flags.GetMaxLen(); max_len != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting max_segment_length to %d\n", max_len)
|
||||||
|
context.SetMaxSegmentLength(max_len)
|
||||||
|
}
|
||||||
|
if max_tokens := flags.GetMaxTokens(); max_tokens != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting max_tokens to %d\n", max_tokens)
|
||||||
|
context.SetMaxTokensPerSegment(max_tokens)
|
||||||
|
}
|
||||||
|
if word_threshold := flags.GetWordThreshold(); word_threshold != 0 {
|
||||||
|
fmt.Fprintf(flags.Output(), "Setting word_threshold to %f\n", word_threshold)
|
||||||
|
context.SetTokenThreshold(word_threshold)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PRIVATE METHODS
|
||||||
|
|
||||||
|
func registerFlags(flag *Flags) {
|
||||||
|
flag.String("model", "", "Path to the model file")
|
||||||
|
flag.String("language", "", "Spoken language")
|
||||||
|
flag.Bool("translate", false, "Translate from source language to english")
|
||||||
|
flag.Duration("offset", 0, "Time offset")
|
||||||
|
flag.Duration("duration", 0, "Duration of audio to process")
|
||||||
|
flag.Uint("threads", 0, "Number of threads to use")
|
||||||
|
flag.Uint("max-len", 0, "Maximum segment length in characters")
|
||||||
|
flag.Uint("max-tokens", 0, "Maximum tokens per segment")
|
||||||
|
flag.Float64("word-thold", 0, "Maximum segment score")
|
||||||
|
flag.Bool("tokens", false, "Display tokens")
|
||||||
|
flag.Bool("colorize", false, "Colorize tokens")
|
||||||
|
flag.String("out", "", "Output format (srt, none or leave as empty string)")
|
||||||
|
}
|
||||||
43
bindings/go/examples/go-whisper/main.go
Normal file
43
bindings/go/examples/go-whisper/main.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
// Packages
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flags, err := NewFlags(filepath.Base(os.Args[0]), os.Args[1:])
|
||||||
|
if err == flag.ErrHelp {
|
||||||
|
os.Exit(0)
|
||||||
|
} else if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
} else if flags.GetModel() == "" {
|
||||||
|
fmt.Fprintln(os.Stderr, "Use -model flag to specify which model file to use")
|
||||||
|
os.Exit(1)
|
||||||
|
} else if flags.NArg() == 0 {
|
||||||
|
fmt.Fprintln(os.Stderr, "No input files specified")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load model
|
||||||
|
model, err := whisper.New(flags.GetModel())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
// Process files
|
||||||
|
for _, filename := range flags.Args() {
|
||||||
|
if err := Process(model, filename, flags); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
132
bindings/go/examples/go-whisper/process.go
Normal file
132
bindings/go/examples/go-whisper/process.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// Package imports
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
wav "github.com/go-audio/wav"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Process(model whisper.Model, path string, flags *Flags) error {
|
||||||
|
var data []float32
|
||||||
|
|
||||||
|
// Create processing context
|
||||||
|
context, err := model.NewContext()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the parameters
|
||||||
|
if err := flags.SetParams(context); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("\n%s\n", context.SystemInfo())
|
||||||
|
|
||||||
|
// Open the file
|
||||||
|
fmt.Fprintf(flags.Output(), "Loading %q\n", path)
|
||||||
|
fh, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Decode the WAV file - load the full buffer
|
||||||
|
dec := wav.NewDecoder(fh)
|
||||||
|
if buf, err := dec.FullPCMBuffer(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if dec.SampleRate != whisper.SampleRate {
|
||||||
|
return fmt.Errorf("unsupported sample rate: %d", dec.SampleRate)
|
||||||
|
} else if dec.NumChans != 1 {
|
||||||
|
return fmt.Errorf("unsupported number of channels: %d", dec.NumChans)
|
||||||
|
} else {
|
||||||
|
data = buf.AsFloat32Buffer().Data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segment callback when -tokens is specified
|
||||||
|
var cb whisper.SegmentCallback
|
||||||
|
if flags.IsTokens() {
|
||||||
|
cb = func(segment whisper.Segment) {
|
||||||
|
fmt.Fprintf(flags.Output(), "%02d [%6s->%6s] ", segment.Num, segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond))
|
||||||
|
for _, token := range segment.Tokens {
|
||||||
|
if flags.IsColorize() && context.IsText(token) {
|
||||||
|
fmt.Fprint(flags.Output(), Colorize(token.Text, int(token.P*24.0)), " ")
|
||||||
|
} else {
|
||||||
|
fmt.Fprint(flags.Output(), token.Text, " ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprintln(flags.Output(), "")
|
||||||
|
fmt.Fprintln(flags.Output(), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the data
|
||||||
|
fmt.Fprintf(flags.Output(), " ...processing %q\n", path)
|
||||||
|
context.ResetTimings()
|
||||||
|
if err := context.Process(data, nil, cb, nil); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
context.PrintTimings()
|
||||||
|
|
||||||
|
// Print out the results
|
||||||
|
switch {
|
||||||
|
case flags.GetOut() == "srt":
|
||||||
|
return OutputSRT(os.Stdout, context)
|
||||||
|
case flags.GetOut() == "none":
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return Output(os.Stdout, context, flags.IsColorize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output text as SRT file
|
||||||
|
func OutputSRT(w io.Writer, context whisper.Context) error {
|
||||||
|
n := 1
|
||||||
|
for {
|
||||||
|
segment, err := context.NextSegment()
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintln(w, n)
|
||||||
|
fmt.Fprintln(w, srtTimestamp(segment.Start), " --> ", srtTimestamp(segment.End))
|
||||||
|
fmt.Fprintln(w, segment.Text)
|
||||||
|
fmt.Fprintln(w, "")
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output text to terminal
|
||||||
|
func Output(w io.Writer, context whisper.Context, colorize bool) error {
|
||||||
|
for {
|
||||||
|
segment, err := context.NextSegment()
|
||||||
|
if err == io.EOF {
|
||||||
|
return nil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "[%6s->%6s]", segment.Start.Truncate(time.Millisecond), segment.End.Truncate(time.Millisecond))
|
||||||
|
if colorize {
|
||||||
|
for _, token := range segment.Tokens {
|
||||||
|
if !context.IsText(token) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, " ", Colorize(token.Text, int(token.P*24.0)))
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, "\n")
|
||||||
|
} else {
|
||||||
|
fmt.Fprintln(w, " ", segment.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return srtTimestamp
|
||||||
|
func srtTimestamp(t time.Duration) string {
|
||||||
|
return fmt.Sprintf("%02d:%02d:%02d,%03d", t/time.Hour, (t%time.Hour)/time.Minute, (t%time.Minute)/time.Second, (t%time.Second)/time.Millisecond)
|
||||||
|
}
|
||||||
16
bindings/go/go.mod
Normal file
16
bindings/go/go.mod
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module github.com/ggerganov/whisper.cpp/bindings/go
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/go-audio/wav v1.1.0
|
||||||
|
github.com/stretchr/testify v1.9.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/go-audio/audio v1.0.0 // indirect
|
||||||
|
github.com/go-audio/riff v1.0.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
16
bindings/go/go.sum
Normal file
16
bindings/go/go.sum
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-audio/audio v1.0.0 h1:zS9vebldgbQqktK4H0lUqWrG8P0NxCJVqcj7ZpNnwd4=
|
||||||
|
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
|
||||||
|
github.com/go-audio/riff v1.0.0 h1:d8iCGbDvox9BfLagY94fBynxSPHO80LmZCaOsmKxokA=
|
||||||
|
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
|
||||||
|
github.com/go-audio/wav v1.1.0 h1:jQgLtbqBzY7G+BM8fXF7AHUk1uHUviWS4X39d5rsL2g=
|
||||||
|
github.com/go-audio/wav v1.1.0/go.mod h1:mpe9qfwbScEbkd8uybLuIpTgHyrISw/OTuvjUW2iGtE=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
244
bindings/go/params.go
Normal file
244
bindings/go/params.go
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CGO
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <whisper.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
func (p *Params) SetTranslate(v bool) {
|
||||||
|
p.translate = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetSplitOnWord(v bool) {
|
||||||
|
p.split_on_word = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetNoContext(v bool) {
|
||||||
|
p.no_context = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetSingleSegment(v bool) {
|
||||||
|
p.single_segment = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetPrintSpecial(v bool) {
|
||||||
|
p.print_special = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetPrintProgress(v bool) {
|
||||||
|
p.print_progress = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetPrintRealtime(v bool) {
|
||||||
|
p.print_realtime = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetPrintTimestamps(v bool) {
|
||||||
|
p.print_timestamps = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Voice Activity Detection (VAD)
|
||||||
|
func (p *Params) SetVAD(v bool) {
|
||||||
|
p.vad = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADModelPath(path string) {
|
||||||
|
p.vad_model_path = C.CString(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADThreshold(t float32) {
|
||||||
|
p.vad_params.threshold = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADMinSpeechMs(ms int) {
|
||||||
|
p.vad_params.min_speech_duration_ms = C.int(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADMinSilenceMs(ms int) {
|
||||||
|
p.vad_params.min_silence_duration_ms = C.int(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADMaxSpeechSec(s float32) {
|
||||||
|
p.vad_params.max_speech_duration_s = C.float(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADSpeechPadMs(ms int) {
|
||||||
|
p.vad_params.speech_pad_ms = C.int(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetVADSamplesOverlap(sec float32) {
|
||||||
|
p.vad_params.samples_overlap = C.float(sec)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set language id
|
||||||
|
func (p *Params) SetLanguage(lang int) error {
|
||||||
|
if lang == -1 {
|
||||||
|
p.language = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
str := C.whisper_lang_str(C.int(lang))
|
||||||
|
if str == nil {
|
||||||
|
return ErrInvalidLanguage
|
||||||
|
} else {
|
||||||
|
p.language = str
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get language id
|
||||||
|
func (p *Params) Language() int {
|
||||||
|
if p.language == nil {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return int(C.whisper_lang_id(p.language))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Threads available
|
||||||
|
func (p *Params) Threads() int {
|
||||||
|
return int(p.n_threads)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set number of threads to use
|
||||||
|
func (p *Params) SetThreads(threads int) {
|
||||||
|
p.n_threads = C.int(threads)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set start offset in ms
|
||||||
|
func (p *Params) SetOffset(offset_ms int) {
|
||||||
|
p.offset_ms = C.int(offset_ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set audio duration to process in ms
|
||||||
|
func (p *Params) SetDuration(duration_ms int) {
|
||||||
|
p.duration_ms = C.int(duration_ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestamp token probability threshold (~0.01)
|
||||||
|
func (p *Params) SetTokenThreshold(t float32) {
|
||||||
|
p.thold_pt = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestamp token sum probability threshold (~0.01)
|
||||||
|
func (p *Params) SetTokenSumThreshold(t float32) {
|
||||||
|
p.thold_ptsum = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set max segment length in characters
|
||||||
|
func (p *Params) SetMaxSegmentLength(n int) {
|
||||||
|
p.max_len = C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetTokenTimestamps(b bool) {
|
||||||
|
p.token_timestamps = toBool(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set max tokens per segment (0 = no limit)
|
||||||
|
func (p *Params) SetMaxTokensPerSegment(n int) {
|
||||||
|
p.max_tokens = C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set audio encoder context
|
||||||
|
func (p *Params) SetAudioCtx(n int) {
|
||||||
|
p.audio_ctx = C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetMaxContext(n int) {
|
||||||
|
p.n_max_text_ctx = C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetBeamSize(n int) {
|
||||||
|
p.beam_search.beam_size = C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetEntropyThold(t float32) {
|
||||||
|
p.entropy_thold = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetTemperature(t float32) {
|
||||||
|
p.temperature = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the fallback temperature incrementation
|
||||||
|
// Pass -1.0 to disable this feature
|
||||||
|
func (p *Params) SetTemperatureFallback(t float32) {
|
||||||
|
p.temperature_inc = C.float(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set initial prompt
|
||||||
|
func (p *Params) SetInitialPrompt(prompt string) {
|
||||||
|
p.initial_prompt = C.CString(prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Params) SetCarryInitialPrompt(v bool) {
|
||||||
|
p.carry_initial_prompt = toBool(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PRIVATE METHODS
|
||||||
|
|
||||||
|
func toBool(v bool) C.bool {
|
||||||
|
if v {
|
||||||
|
return C.bool(true)
|
||||||
|
}
|
||||||
|
return C.bool(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// STRINGIFY
|
||||||
|
|
||||||
|
func (p *Params) String() string {
|
||||||
|
str := "<whisper.params"
|
||||||
|
str += fmt.Sprintf(" strategy=%v", p.strategy)
|
||||||
|
str += fmt.Sprintf(" n_threads=%d", p.n_threads)
|
||||||
|
if p.language != nil {
|
||||||
|
str += fmt.Sprintf(" language=%s", C.GoString(p.language))
|
||||||
|
}
|
||||||
|
str += fmt.Sprintf(" n_max_text_ctx=%d", p.n_max_text_ctx)
|
||||||
|
str += fmt.Sprintf(" offset_ms=%d", p.offset_ms)
|
||||||
|
str += fmt.Sprintf(" duration_ms=%d", p.duration_ms)
|
||||||
|
str += fmt.Sprintf(" audio_ctx=%d", p.audio_ctx)
|
||||||
|
str += fmt.Sprintf(" initial_prompt=%s", C.GoString(p.initial_prompt))
|
||||||
|
str += fmt.Sprintf(" entropy_thold=%f", p.entropy_thold)
|
||||||
|
str += fmt.Sprintf(" temperature=%f", p.temperature)
|
||||||
|
str += fmt.Sprintf(" temperature_inc=%f", p.temperature_inc)
|
||||||
|
str += fmt.Sprintf(" beam_size=%d", p.beam_search.beam_size)
|
||||||
|
if p.translate {
|
||||||
|
str += " translate"
|
||||||
|
}
|
||||||
|
if p.no_context {
|
||||||
|
str += " no_context"
|
||||||
|
}
|
||||||
|
if p.single_segment {
|
||||||
|
str += " single_segment"
|
||||||
|
}
|
||||||
|
if p.print_special {
|
||||||
|
str += " print_special"
|
||||||
|
}
|
||||||
|
if p.print_progress {
|
||||||
|
str += " print_progress"
|
||||||
|
}
|
||||||
|
if p.print_realtime {
|
||||||
|
str += " print_realtime"
|
||||||
|
}
|
||||||
|
if p.print_timestamps {
|
||||||
|
str += " print_timestamps"
|
||||||
|
}
|
||||||
|
if p.token_timestamps {
|
||||||
|
str += " token_timestamps"
|
||||||
|
}
|
||||||
|
if p.carry_initial_prompt {
|
||||||
|
str += " carry_initial_prompt"
|
||||||
|
}
|
||||||
|
|
||||||
|
return str + ">"
|
||||||
|
}
|
||||||
28
bindings/go/pkg/whisper/consts.go
Normal file
28
bindings/go/pkg/whisper/consts.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ERRORS
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrUnableToLoadModel = errors.New("unable to load model")
|
||||||
|
ErrInternalAppError = errors.New("internal application error")
|
||||||
|
ErrProcessingFailed = errors.New("processing failed")
|
||||||
|
ErrUnsupportedLanguage = errors.New("unsupported language")
|
||||||
|
ErrModelNotMultilingual = errors.New("model is not multilingual")
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CONSTANTS
|
||||||
|
|
||||||
|
// SampleRate is the sample rate of the audio data.
|
||||||
|
const SampleRate = whisper.SampleRate
|
||||||
|
|
||||||
|
// SampleBits is the number of bytes per sample.
|
||||||
|
const SampleBits = whisper.SampleBits
|
||||||
385
bindings/go/pkg/whisper/context.go
Normal file
385
bindings/go/pkg/whisper/context.go
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TYPES
|
||||||
|
|
||||||
|
type context struct {
|
||||||
|
n int
|
||||||
|
model *model
|
||||||
|
params whisper.Params
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure context adheres to the interface
|
||||||
|
var _ Context = (*context)(nil)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LIFECYCLE
|
||||||
|
|
||||||
|
func newContext(model *model, params whisper.Params) (Context, error) {
|
||||||
|
context := new(context)
|
||||||
|
context.model = model
|
||||||
|
context.params = params
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return context, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
// Set the language to use for speech recognition.
|
||||||
|
func (context *context) SetLanguage(lang string) error {
|
||||||
|
if context.model.ctx == nil {
|
||||||
|
return ErrInternalAppError
|
||||||
|
}
|
||||||
|
if !context.model.IsMultilingual() {
|
||||||
|
return ErrModelNotMultilingual
|
||||||
|
}
|
||||||
|
|
||||||
|
if lang == "auto" {
|
||||||
|
context.params.SetLanguage(-1)
|
||||||
|
} else if id := context.model.ctx.Whisper_lang_id(lang); id < 0 {
|
||||||
|
return ErrUnsupportedLanguage
|
||||||
|
} else if err := context.params.SetLanguage(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Return success
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) IsMultilingual() bool {
|
||||||
|
return context.model.IsMultilingual()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get language
|
||||||
|
func (context *context) Language() string {
|
||||||
|
id := context.params.Language()
|
||||||
|
if id == -1 {
|
||||||
|
return "auto"
|
||||||
|
}
|
||||||
|
return whisper.Whisper_lang_str(context.params.Language())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) DetectedLanguage() string {
|
||||||
|
return whisper.Whisper_lang_str(context.model.ctx.Whisper_full_lang_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set translate flag
|
||||||
|
func (context *context) SetTranslate(v bool) {
|
||||||
|
context.params.SetTranslate(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Voice Activity Detection (VAD)
|
||||||
|
func (context *context) SetVAD(v bool) {
|
||||||
|
context.params.SetVAD(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADModelPath(path string) {
|
||||||
|
context.params.SetVADModelPath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADThreshold(t float32) {
|
||||||
|
context.params.SetVADThreshold(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADMinSpeechMs(ms int) {
|
||||||
|
context.params.SetVADMinSpeechMs(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADMinSilenceMs(ms int) {
|
||||||
|
context.params.SetVADMinSilenceMs(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADMaxSpeechSec(s float32) {
|
||||||
|
context.params.SetVADMaxSpeechSec(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADSpeechPadMs(ms int) {
|
||||||
|
context.params.SetVADSpeechPadMs(ms)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetVADSamplesOverlap(sec float32) {
|
||||||
|
context.params.SetVADSamplesOverlap(sec)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *context) SetSplitOnWord(v bool) {
|
||||||
|
context.params.SetSplitOnWord(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set number of threads to use
|
||||||
|
func (context *context) SetThreads(v uint) {
|
||||||
|
context.params.SetThreads(int(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set time offset
|
||||||
|
func (context *context) SetOffset(v time.Duration) {
|
||||||
|
context.params.SetOffset(int(v.Milliseconds()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set duration of audio to process
|
||||||
|
func (context *context) SetDuration(v time.Duration) {
|
||||||
|
context.params.SetDuration(int(v.Milliseconds()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestamp token probability threshold (~0.01)
|
||||||
|
func (context *context) SetTokenThreshold(t float32) {
|
||||||
|
context.params.SetTokenThreshold(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set timestamp token sum probability threshold (~0.01)
|
||||||
|
func (context *context) SetTokenSumThreshold(t float32) {
|
||||||
|
context.params.SetTokenSumThreshold(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set max segment length in characters
|
||||||
|
func (context *context) SetMaxSegmentLength(n uint) {
|
||||||
|
context.params.SetMaxSegmentLength(int(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set token timestamps flag
|
||||||
|
func (context *context) SetTokenTimestamps(b bool) {
|
||||||
|
context.params.SetTokenTimestamps(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set max tokens per segment (0 = no limit)
|
||||||
|
func (context *context) SetMaxTokensPerSegment(n uint) {
|
||||||
|
context.params.SetMaxTokensPerSegment(int(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set audio encoder context
|
||||||
|
func (context *context) SetAudioCtx(n uint) {
|
||||||
|
context.params.SetAudioCtx(int(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set maximum number of text context tokens to store
|
||||||
|
func (context *context) SetMaxContext(n int) {
|
||||||
|
context.params.SetMaxContext(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Beam Size
|
||||||
|
func (context *context) SetBeamSize(n int) {
|
||||||
|
context.params.SetBeamSize(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Entropy threshold
|
||||||
|
func (context *context) SetEntropyThold(t float32) {
|
||||||
|
context.params.SetEntropyThold(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Temperature
|
||||||
|
func (context *context) SetTemperature(t float32) {
|
||||||
|
context.params.SetTemperature(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the fallback temperature incrementation
|
||||||
|
// Pass -1.0 to disable this feature
|
||||||
|
func (context *context) SetTemperatureFallback(t float32) {
|
||||||
|
context.params.SetTemperatureFallback(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set initial prompt
|
||||||
|
func (context *context) SetInitialPrompt(prompt string) {
|
||||||
|
context.params.SetInitialPrompt(prompt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetTimings resets the mode timings. Should be called before processing
|
||||||
|
func (context *context) ResetTimings() {
|
||||||
|
context.model.ctx.Whisper_reset_timings()
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintTimings prints the model timings to stdout.
|
||||||
|
func (context *context) PrintTimings() {
|
||||||
|
context.model.ctx.Whisper_print_timings()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemInfo returns the system information
|
||||||
|
func (context *context) SystemInfo() string {
|
||||||
|
return fmt.Sprintf("system_info: n_threads = %d / %d | %s\n",
|
||||||
|
context.params.Threads(),
|
||||||
|
runtime.NumCPU(),
|
||||||
|
whisper.Whisper_print_system_info(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use mel data at offset_ms to try and auto-detect the spoken language
|
||||||
|
// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first.
|
||||||
|
// Returns the probabilities of all languages.
|
||||||
|
func (context *context) WhisperLangAutoDetect(offset_ms int, n_threads int) ([]float32, error) {
|
||||||
|
langProbs, err := context.model.ctx.Whisper_lang_auto_detect(offset_ms, n_threads)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return langProbs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process new sample data and return any errors
|
||||||
|
func (context *context) Process(
|
||||||
|
data []float32,
|
||||||
|
callEncoderBegin EncoderBeginCallback,
|
||||||
|
callNewSegment SegmentCallback,
|
||||||
|
callProgress ProgressCallback,
|
||||||
|
) error {
|
||||||
|
if context.model.ctx == nil {
|
||||||
|
return ErrInternalAppError
|
||||||
|
}
|
||||||
|
// If the callback is defined then we force on single_segment mode
|
||||||
|
if callNewSegment != nil {
|
||||||
|
context.params.SetSingleSegment(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't do parallel processing at the moment
|
||||||
|
processors := 0
|
||||||
|
if processors > 1 {
|
||||||
|
if err := context.model.ctx.Whisper_full_parallel(context.params, data, processors, callEncoderBegin,
|
||||||
|
func(new int) {
|
||||||
|
if callNewSegment != nil {
|
||||||
|
num_segments := context.model.ctx.Whisper_full_n_segments()
|
||||||
|
s0 := num_segments - new
|
||||||
|
for i := s0; i < num_segments; i++ {
|
||||||
|
callNewSegment(toSegment(context.model.ctx, i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if err := context.model.ctx.Whisper_full(context.params, data, callEncoderBegin,
|
||||||
|
func(new int) {
|
||||||
|
if callNewSegment != nil {
|
||||||
|
num_segments := context.model.ctx.Whisper_full_n_segments()
|
||||||
|
s0 := num_segments - new
|
||||||
|
for i := s0; i < num_segments; i++ {
|
||||||
|
callNewSegment(toSegment(context.model.ctx, i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, func(progress int) {
|
||||||
|
if callProgress != nil {
|
||||||
|
callProgress(progress)
|
||||||
|
}
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset n so that more Segments can be available within NextSegment call
|
||||||
|
context.n = 0
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the next segment of tokens
|
||||||
|
func (context *context) NextSegment() (Segment, error) {
|
||||||
|
if context.model.ctx == nil {
|
||||||
|
return Segment{}, ErrInternalAppError
|
||||||
|
}
|
||||||
|
if context.n >= context.model.ctx.Whisper_full_n_segments() {
|
||||||
|
return Segment{}, io.EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate result
|
||||||
|
result := toSegment(context.model.ctx, context.n)
|
||||||
|
|
||||||
|
// Increment the cursor
|
||||||
|
context.n++
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for text tokens
|
||||||
|
func (context *context) IsText(t Token) bool {
|
||||||
|
switch {
|
||||||
|
case context.IsBEG(t):
|
||||||
|
return false
|
||||||
|
case context.IsSOT(t):
|
||||||
|
return false
|
||||||
|
case whisper.Token(t.Id) >= context.model.ctx.Whisper_token_eot():
|
||||||
|
return false
|
||||||
|
case context.IsPREV(t):
|
||||||
|
return false
|
||||||
|
case context.IsSOLM(t):
|
||||||
|
return false
|
||||||
|
case context.IsNOT(t):
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "begin" token
|
||||||
|
func (context *context) IsBEG(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_beg()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "start of transcription" token
|
||||||
|
func (context *context) IsSOT(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_sot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "end of transcription" token
|
||||||
|
func (context *context) IsEOT(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_eot()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "start of prev" token
|
||||||
|
func (context *context) IsPREV(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_prev()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "start of lm" token
|
||||||
|
func (context *context) IsSOLM(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_solm()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for "No timestamps" token
|
||||||
|
func (context *context) IsNOT(t Token) bool {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_not()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for token associated with a specific language
|
||||||
|
func (context *context) IsLANG(t Token, lang string) bool {
|
||||||
|
if id := context.model.ctx.Whisper_lang_id(lang); id >= 0 {
|
||||||
|
return whisper.Token(t.Id) == context.model.ctx.Whisper_token_lang(id)
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PRIVATE METHODS
|
||||||
|
|
||||||
|
func toSegment(ctx *whisper.Context, n int) Segment {
|
||||||
|
return Segment{
|
||||||
|
Num: n,
|
||||||
|
Text: strings.TrimSpace(ctx.Whisper_full_get_segment_text(n)),
|
||||||
|
Start: time.Duration(ctx.Whisper_full_get_segment_t0(n)) * time.Millisecond * 10,
|
||||||
|
End: time.Duration(ctx.Whisper_full_get_segment_t1(n)) * time.Millisecond * 10,
|
||||||
|
Tokens: toTokens(ctx, n),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toTokens(ctx *whisper.Context, n int) []Token {
|
||||||
|
result := make([]Token, ctx.Whisper_full_n_tokens(n))
|
||||||
|
for i := 0; i < len(result); i++ {
|
||||||
|
data := ctx.Whisper_full_get_token_data(n, i)
|
||||||
|
|
||||||
|
result[i] = Token{
|
||||||
|
Id: int(ctx.Whisper_full_get_token_id(n, i)),
|
||||||
|
Text: ctx.Whisper_full_get_token_text(n, i),
|
||||||
|
P: ctx.Whisper_full_get_token_p(n, i),
|
||||||
|
Start: time.Duration(data.T0()) * time.Millisecond * 10,
|
||||||
|
End: time.Duration(data.T1()) * time.Millisecond * 10,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
172
bindings/go/pkg/whisper/context_test.go
Normal file
172
bindings/go/pkg/whisper/context_test.go
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
package whisper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
"github.com/go-audio/wav"
|
||||||
|
assert "github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetLanguage(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// This returns an error since
|
||||||
|
// the model 'models/ggml-small.en.bin'
|
||||||
|
// that is loaded is not multilingual
|
||||||
|
err = context.SetLanguage("en")
|
||||||
|
assert.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContextModelIsMultilingual(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
isMultilingual := context.IsMultilingual()
|
||||||
|
|
||||||
|
// This returns false since
|
||||||
|
// the model 'models/ggml-small.en.bin'
|
||||||
|
// that is loaded is not multilingual
|
||||||
|
assert.False(isMultilingual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLanguage(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// This always returns en since
|
||||||
|
// the model 'models/ggml-small.en.bin'
|
||||||
|
// that is loaded is not multilingual
|
||||||
|
expectedLanguage := "en"
|
||||||
|
actualLanguage := context.Language()
|
||||||
|
assert.Equal(expectedLanguage, actualLanguage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcess(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
fh, err := os.Open(SamplePath)
|
||||||
|
assert.NoError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Decode the WAV file - load the full buffer
|
||||||
|
dec := wav.NewDecoder(fh)
|
||||||
|
buf, err := dec.FullPCMBuffer()
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(uint16(1), dec.NumChans)
|
||||||
|
|
||||||
|
data := buf.AsFloat32Buffer().Data
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
err = context.Process(data, nil, nil, nil)
|
||||||
|
assert.NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProcessMaxTokensPerSegment(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
if _, err := os.Stat(ModelPath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, model not found:", ModelPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
fh, err := os.Open(SamplePath)
|
||||||
|
assert.NoError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Decode the WAV file - load the full buffer
|
||||||
|
dec := wav.NewDecoder(fh)
|
||||||
|
buf, err := dec.FullPCMBuffer()
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(uint16(1), dec.NumChans)
|
||||||
|
|
||||||
|
data := buf.AsFloat32Buffer().Data
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
context.SetMaxTokensPerSegment(5)
|
||||||
|
|
||||||
|
err = context.Process(data, nil, nil, nil)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
var text strings.Builder
|
||||||
|
nSegments := 0
|
||||||
|
for {
|
||||||
|
segment, err := context.NextSegment()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nSegments++
|
||||||
|
text.WriteString(segment.Text)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Greater(nSegments, 1)
|
||||||
|
assert.Contains(text.String(), "country")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDetectedLanguage(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
fh, err := os.Open(SamplePath)
|
||||||
|
assert.NoError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Decode the WAV file - load the full buffer
|
||||||
|
dec := wav.NewDecoder(fh)
|
||||||
|
buf, err := dec.FullPCMBuffer()
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.Equal(uint16(1), dec.NumChans)
|
||||||
|
|
||||||
|
data := buf.AsFloat32Buffer().Data
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
err = context.Process(data, nil, nil, nil)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
expectedLanguage := "en"
|
||||||
|
actualLanguage := context.DetectedLanguage()
|
||||||
|
assert.Equal(expectedLanguage, actualLanguage)
|
||||||
|
}
|
||||||
4
bindings/go/pkg/whisper/doc.go
Normal file
4
bindings/go/pkg/whisper/doc.go
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
/*
|
||||||
|
This is the higher-level speech-to-text whisper.cpp API for go
|
||||||
|
*/
|
||||||
|
package whisper
|
||||||
118
bindings/go/pkg/whisper/interface.go
Normal file
118
bindings/go/pkg/whisper/interface.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TYPES
|
||||||
|
|
||||||
|
// SegmentCallback is the callback function for processing segments in real
|
||||||
|
// time. It is called during the Process function
|
||||||
|
type SegmentCallback func(Segment)
|
||||||
|
|
||||||
|
// ProgressCallback is the callback function for reporting progress during
|
||||||
|
// processing. It is called during the Process function
|
||||||
|
type ProgressCallback func(int)
|
||||||
|
|
||||||
|
// EncoderBeginCallback is the callback function for checking if we want to
|
||||||
|
// continue processing. It is called during the Process function
|
||||||
|
type EncoderBeginCallback func() bool
|
||||||
|
|
||||||
|
// Model is the interface to a whisper model. Create a new model with the
|
||||||
|
// function whisper.New(string)
|
||||||
|
type Model interface {
|
||||||
|
io.Closer
|
||||||
|
|
||||||
|
// Return a new speech-to-text context.
|
||||||
|
NewContext() (Context, error)
|
||||||
|
|
||||||
|
// Return true if the model is multilingual.
|
||||||
|
IsMultilingual() bool
|
||||||
|
|
||||||
|
// Return all languages supported.
|
||||||
|
Languages() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Context is the speech recognition context.
|
||||||
|
type Context interface {
|
||||||
|
SetLanguage(string) error // Set the language to use for speech recognition, use "auto" for auto detect language.
|
||||||
|
SetTranslate(bool) // Set translate flag
|
||||||
|
IsMultilingual() bool // Return true if the model is multilingual.
|
||||||
|
Language() string // Get language
|
||||||
|
DetectedLanguage() string // Get detected language
|
||||||
|
|
||||||
|
SetOffset(time.Duration) // Set offset
|
||||||
|
SetDuration(time.Duration) // Set duration
|
||||||
|
SetThreads(uint) // Set number of threads to use
|
||||||
|
SetSplitOnWord(bool) // Set split on word flag
|
||||||
|
SetTokenThreshold(float32) // Set timestamp token probability threshold
|
||||||
|
SetTokenSumThreshold(float32) // Set timestamp token sum probability threshold
|
||||||
|
SetMaxSegmentLength(uint) // Set max segment length in characters
|
||||||
|
SetTokenTimestamps(bool) // Set token timestamps flag
|
||||||
|
SetMaxTokensPerSegment(uint) // Set max tokens per segment (0 = no limit)
|
||||||
|
SetAudioCtx(uint) // Set audio encoder context
|
||||||
|
SetMaxContext(n int) // Set maximum number of text context tokens to store
|
||||||
|
SetBeamSize(n int) // Set Beam Size
|
||||||
|
SetEntropyThold(t float32) // Set Entropy threshold
|
||||||
|
SetInitialPrompt(prompt string) // Set initial prompt
|
||||||
|
SetTemperature(t float32) // Set temperature
|
||||||
|
SetTemperatureFallback(t float32) // Set temperature incrementation
|
||||||
|
|
||||||
|
SetVAD(v bool)
|
||||||
|
SetVADModelPath(path string)
|
||||||
|
SetVADThreshold(t float32)
|
||||||
|
SetVADMinSpeechMs(ms int)
|
||||||
|
SetVADMinSilenceMs(ms int)
|
||||||
|
SetVADMaxSpeechSec(s float32)
|
||||||
|
SetVADSpeechPadMs(ms int)
|
||||||
|
SetVADSamplesOverlap(sec float32)
|
||||||
|
|
||||||
|
// Process mono audio data and return any errors.
|
||||||
|
// If defined, newly generated segments are passed to the
|
||||||
|
// callback function during processing.
|
||||||
|
Process([]float32, EncoderBeginCallback, SegmentCallback, ProgressCallback) error
|
||||||
|
|
||||||
|
// After process is called, return segments until the end of the stream
|
||||||
|
// is reached, when io.EOF is returned.
|
||||||
|
NextSegment() (Segment, error)
|
||||||
|
|
||||||
|
IsBEG(Token) bool // Test for "begin" token
|
||||||
|
IsSOT(Token) bool // Test for "start of transcription" token
|
||||||
|
IsEOT(Token) bool // Test for "end of transcription" token
|
||||||
|
IsPREV(Token) bool // Test for "start of prev" token
|
||||||
|
IsSOLM(Token) bool // Test for "start of lm" token
|
||||||
|
IsNOT(Token) bool // Test for "No timestamps" token
|
||||||
|
IsLANG(Token, string) bool // Test for token associated with a specific language
|
||||||
|
IsText(Token) bool // Test for text token
|
||||||
|
|
||||||
|
// Timings
|
||||||
|
PrintTimings()
|
||||||
|
ResetTimings()
|
||||||
|
|
||||||
|
SystemInfo() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Segment is the text result of a speech recognition.
|
||||||
|
type Segment struct {
|
||||||
|
// Segment Number
|
||||||
|
Num int
|
||||||
|
|
||||||
|
// Time beginning and end timestamps for the segment.
|
||||||
|
Start, End time.Duration
|
||||||
|
|
||||||
|
// The text of the segment.
|
||||||
|
Text string
|
||||||
|
|
||||||
|
// The tokens of the segment.
|
||||||
|
Tokens []Token
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token is a text or special token
|
||||||
|
type Token struct {
|
||||||
|
Id int
|
||||||
|
Text string
|
||||||
|
P float32
|
||||||
|
Start, End time.Duration
|
||||||
|
}
|
||||||
101
bindings/go/pkg/whisper/model.go
Normal file
101
bindings/go/pkg/whisper/model.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
// Bindings
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TYPES
|
||||||
|
|
||||||
|
type model struct {
|
||||||
|
path string
|
||||||
|
ctx *whisper.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure model adheres to the interface
|
||||||
|
var _ Model = (*model)(nil)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LIFECYCLE
|
||||||
|
|
||||||
|
func New(path string) (Model, error) {
|
||||||
|
model := new(model)
|
||||||
|
if _, err := os.Stat(path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if ctx := whisper.Whisper_init(path); ctx == nil {
|
||||||
|
return nil, ErrUnableToLoadModel
|
||||||
|
} else {
|
||||||
|
model.ctx = ctx
|
||||||
|
model.path = path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return model, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (model *model) Close() error {
|
||||||
|
if model.ctx != nil {
|
||||||
|
model.ctx.Whisper_free()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release resources
|
||||||
|
model.ctx = nil
|
||||||
|
|
||||||
|
// Return success
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// STRINGIFY
|
||||||
|
|
||||||
|
func (model *model) String() string {
|
||||||
|
str := "<whisper.model"
|
||||||
|
if model.ctx != nil {
|
||||||
|
str += fmt.Sprintf(" model=%q", model.path)
|
||||||
|
}
|
||||||
|
return str + ">"
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
// Return true if model is multilingual (language and translation options are supported)
|
||||||
|
func (model *model) IsMultilingual() bool {
|
||||||
|
return model.ctx.Whisper_is_multilingual() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return all recognized languages. Initially it is set to auto-detect
|
||||||
|
func (model *model) Languages() []string {
|
||||||
|
result := make([]string, 0, whisper.Whisper_lang_max_id())
|
||||||
|
for i := 0; i < whisper.Whisper_lang_max_id(); i++ {
|
||||||
|
str := whisper.Whisper_lang_str(i)
|
||||||
|
if model.ctx.Whisper_lang_id(str) >= 0 {
|
||||||
|
result = append(result, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (model *model) NewContext() (Context, error) {
|
||||||
|
if model.ctx == nil {
|
||||||
|
return nil, ErrInternalAppError
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new context
|
||||||
|
params := model.ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY)
|
||||||
|
params.SetTranslate(false)
|
||||||
|
params.SetPrintSpecial(false)
|
||||||
|
params.SetPrintProgress(false)
|
||||||
|
params.SetPrintRealtime(false)
|
||||||
|
params.SetPrintTimestamps(false)
|
||||||
|
params.SetThreads(runtime.NumCPU())
|
||||||
|
params.SetNoContext(true)
|
||||||
|
|
||||||
|
// Return new context
|
||||||
|
return newContext(model, params)
|
||||||
|
}
|
||||||
91
bindings/go/pkg/whisper/model_test.go
Normal file
91
bindings/go/pkg/whisper/model_test.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package whisper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ggerganov/whisper.cpp/bindings/go/pkg/whisper"
|
||||||
|
assert "github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
t.Run("valid model path", func(t *testing.T) {
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid model path", func(t *testing.T) {
|
||||||
|
invalidModelPath := "invalid-model-path.bin"
|
||||||
|
model, err := whisper.New(invalidModelPath)
|
||||||
|
assert.Error(err)
|
||||||
|
assert.Nil(model)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClose(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
|
||||||
|
err = model.Close()
|
||||||
|
assert.NoError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewContext(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
context, err := model.NewContext()
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsMultilingual(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
isMultilingual := model.IsMultilingual()
|
||||||
|
|
||||||
|
// This returns false since
|
||||||
|
// the model 'models/ggml-small.en.bin'
|
||||||
|
// that is loaded is not multilingual
|
||||||
|
assert.False(isMultilingual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLanguages(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
model, err := whisper.New(ModelPath)
|
||||||
|
assert.NoError(err)
|
||||||
|
assert.NotNil(model)
|
||||||
|
defer model.Close()
|
||||||
|
|
||||||
|
expectedLanguages := []string{
|
||||||
|
"en", "zh", "de", "es", "ru", "ko", "fr", "ja", "pt", "tr", "pl",
|
||||||
|
"ca", "nl", "ar", "sv", "it", "id", "hi", "fi", "vi", "he", "uk",
|
||||||
|
"el", "ms", "cs", "ro", "da", "hu", "ta", "no", "th", "ur", "hr",
|
||||||
|
"bg", "lt", "la", "mi", "ml", "cy", "sk", "te", "fa", "lv", "bn",
|
||||||
|
"sr", "az", "sl", "kn", "et", "mk", "br", "eu", "is", "hy", "ne",
|
||||||
|
"mn", "bs", "kk", "sq", "sw", "gl", "mr", "pa", "si", "km", "sn",
|
||||||
|
"yo", "so", "af", "oc", "ka", "be", "tg", "sd", "gu", "am", "yi",
|
||||||
|
"lo", "uz", "fo", "ht", "ps", "tk", "nn", "mt", "sa", "lb", "my",
|
||||||
|
"bo", "tl", "mg", "as", "tt", "haw", "ln", "ha", "ba", "jw", "su",
|
||||||
|
}
|
||||||
|
|
||||||
|
actualLanguages := model.Languages()
|
||||||
|
|
||||||
|
assert.Equal(expectedLanguages, actualLanguages)
|
||||||
|
}
|
||||||
6
bindings/go/pkg/whisper/util_test.go
Normal file
6
bindings/go/pkg/whisper/util_test.go
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
package whisper_test
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModelPath = "../../models/ggml-small.en.bin"
|
||||||
|
SamplePath = "../../samples/jfk.wav"
|
||||||
|
)
|
||||||
BIN
bindings/go/samples/jfk.wav
Normal file
BIN
bindings/go/samples/jfk.wav
Normal file
Binary file not shown.
470
bindings/go/whisper.go
Normal file
470
bindings/go/whisper.go
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
package whisper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CGO
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo LDFLAGS: -lwhisper -lggml -lggml-base -lggml-cpu -lm -lstdc++
|
||||||
|
#cgo linux LDFLAGS: -fopenmp
|
||||||
|
#cgo darwin LDFLAGS: -lggml-metal -lggml-blas
|
||||||
|
#cgo darwin LDFLAGS: -framework Accelerate -framework Metal -framework Foundation -framework CoreGraphics
|
||||||
|
#include <whisper.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
extern void callNewSegment(void* user_data, int new);
|
||||||
|
extern void callProgress(void* user_data, int progress);
|
||||||
|
extern bool callEncoderBegin(void* user_data);
|
||||||
|
|
||||||
|
// Text segment callback
|
||||||
|
// Called on every newly generated text segment
|
||||||
|
// Use the whisper_full_...() functions to obtain the text segments
|
||||||
|
static void whisper_new_segment_cb(struct whisper_context* ctx, struct whisper_state* state, int n_new, void* user_data) {
|
||||||
|
if(user_data != NULL && ctx != NULL) {
|
||||||
|
callNewSegment(user_data, n_new);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress callback
|
||||||
|
// Called on every newly generated text segment
|
||||||
|
// Use the whisper_full_...() functions to obtain the text segments
|
||||||
|
static void whisper_progress_cb(struct whisper_context* ctx, struct whisper_state* state, int progress, void* user_data) {
|
||||||
|
if(user_data != NULL && ctx != NULL) {
|
||||||
|
callProgress(user_data, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encoder begin callback
|
||||||
|
// If not NULL, called before the encoder starts
|
||||||
|
// If it returns false, the computation is aborted
|
||||||
|
static bool whisper_encoder_begin_cb(struct whisper_context* ctx, struct whisper_state* state, void* user_data) {
|
||||||
|
if(user_data != NULL && ctx != NULL) {
|
||||||
|
return callEncoderBegin(user_data);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get default parameters and set callbacks
|
||||||
|
static struct whisper_full_params whisper_full_default_params_cb(struct whisper_context* ctx, enum whisper_sampling_strategy strategy) {
|
||||||
|
struct whisper_full_params params = whisper_full_default_params(strategy);
|
||||||
|
params.new_segment_callback = whisper_new_segment_cb;
|
||||||
|
params.new_segment_callback_user_data = (void*)(ctx);
|
||||||
|
params.encoder_begin_callback = whisper_encoder_begin_cb;
|
||||||
|
params.encoder_begin_callback_user_data = (void*)(ctx);
|
||||||
|
params.progress_callback = whisper_progress_cb;
|
||||||
|
params.progress_callback_user_data = (void*)(ctx);
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TYPES
|
||||||
|
|
||||||
|
type (
|
||||||
|
Context C.struct_whisper_context
|
||||||
|
Token C.whisper_token
|
||||||
|
TokenData C.struct_whisper_token_data
|
||||||
|
SamplingStrategy C.enum_whisper_sampling_strategy
|
||||||
|
Params C.struct_whisper_full_params
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GLOBALS
|
||||||
|
|
||||||
|
const (
|
||||||
|
SAMPLING_GREEDY SamplingStrategy = C.WHISPER_SAMPLING_GREEDY
|
||||||
|
SAMPLING_BEAM_SEARCH SamplingStrategy = C.WHISPER_SAMPLING_BEAM_SEARCH
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SampleRate = C.WHISPER_SAMPLE_RATE // Expected sample rate, samples per second
|
||||||
|
SampleBits = uint16(unsafe.Sizeof(C.float(0))) * 8 // Sample size in bits
|
||||||
|
NumFFT = C.WHISPER_N_FFT
|
||||||
|
HopLength = C.WHISPER_HOP_LENGTH
|
||||||
|
ChunkSize = C.WHISPER_CHUNK_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrTokenizerFailed = errors.New("whisper_tokenize failed")
|
||||||
|
ErrAutoDetectFailed = errors.New("whisper_lang_auto_detect failed")
|
||||||
|
ErrConversionFailed = errors.New("whisper_convert failed")
|
||||||
|
ErrInvalidLanguage = errors.New("invalid language")
|
||||||
|
)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// PUBLIC METHODS
|
||||||
|
|
||||||
|
// Allocates all memory needed for the model and loads the model from the given file.
|
||||||
|
// Returns NULL on failure.
|
||||||
|
func Whisper_init(path string) *Context {
|
||||||
|
cPath := C.CString(path)
|
||||||
|
defer C.free(unsafe.Pointer(cPath))
|
||||||
|
if ctx := C.whisper_init_from_file_with_params(cPath, C.whisper_context_default_params()); ctx != nil {
|
||||||
|
return (*Context)(ctx)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frees all memory allocated by the model.
|
||||||
|
func (ctx *Context) Whisper_free() {
|
||||||
|
C.whisper_free((*C.struct_whisper_context)(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert RAW PCM audio to log mel spectrogram.
|
||||||
|
// The resulting spectrogram is stored inside the provided whisper context.
|
||||||
|
func (ctx *Context) Whisper_pcm_to_mel(data []float32, threads int) error {
|
||||||
|
if C.whisper_pcm_to_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(threads)) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can be used to set a custom log mel spectrogram inside the provided whisper context.
|
||||||
|
// Use this instead of whisper_pcm_to_mel() if you want to provide your own log mel spectrogram.
|
||||||
|
// n_mel must be 80
|
||||||
|
func (ctx *Context) Whisper_set_mel(data []float32, n_mel int) error {
|
||||||
|
if C.whisper_set_mel((*C.struct_whisper_context)(ctx), (*C.float)(&data[0]), C.int(len(data)), C.int(n_mel)) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the Whisper encoder on the log mel spectrogram stored inside the provided whisper context.
|
||||||
|
// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first.
|
||||||
|
// offset can be used to specify the offset of the first frame in the spectrogram.
|
||||||
|
func (ctx *Context) Whisper_encode(offset, threads int) error {
|
||||||
|
if C.whisper_encode((*C.struct_whisper_context)(ctx), C.int(offset), C.int(threads)) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the Whisper decoder to obtain the logits and probabilities for the next token.
|
||||||
|
// Make sure to call whisper_encode() first.
|
||||||
|
// tokens + n_tokens is the provided context for the decoder.
|
||||||
|
// n_past is the number of tokens to use from previous decoder calls.
|
||||||
|
func (ctx *Context) Whisper_decode(tokens []Token, past, threads int) error {
|
||||||
|
if C.whisper_decode((*C.struct_whisper_context)(ctx), (*C.whisper_token)(&tokens[0]), C.int(len(tokens)), C.int(past), C.int(threads)) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the provided text into tokens. The tokens pointer must be large enough to hold the resulting tokens.
|
||||||
|
// Returns the number of tokens on success
|
||||||
|
func (ctx *Context) Whisper_tokenize(text string, tokens []Token) (int, error) {
|
||||||
|
cText := C.CString(text)
|
||||||
|
defer C.free(unsafe.Pointer(cText))
|
||||||
|
if n := C.whisper_tokenize((*C.struct_whisper_context)(ctx), cText, (*C.whisper_token)(&tokens[0]), C.int(len(tokens))); n >= 0 {
|
||||||
|
return int(n), nil
|
||||||
|
} else {
|
||||||
|
return 0, ErrTokenizerFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the id of the specified language, returns -1 if not found
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// "de" -> 2
|
||||||
|
// "german" -> 2
|
||||||
|
func (ctx *Context) Whisper_lang_id(lang string) int {
|
||||||
|
return int(C.whisper_lang_id(C.CString(lang)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Largest language id (i.e. number of available languages - 1)
|
||||||
|
func Whisper_lang_max_id() int {
|
||||||
|
return int(C.whisper_lang_max_id())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the short string of the specified language id (e.g. 2 -> "de"),
|
||||||
|
// returns empty string if not found
|
||||||
|
func Whisper_lang_str(id int) string {
|
||||||
|
return C.GoString(C.whisper_lang_str(C.int(id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use mel data at offset_ms to try and auto-detect the spoken language
|
||||||
|
// Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first.
|
||||||
|
// Returns the probabilities of all languages.
|
||||||
|
// ref: https://github.com/openai/whisper/blob/main/whisper/decoding.py#L18-L69
|
||||||
|
func (ctx *Context) Whisper_lang_auto_detect(offset_ms, n_threads int) ([]float32, error) {
|
||||||
|
probs := make([]float32, Whisper_lang_max_id()+1)
|
||||||
|
if n := int(C.whisper_lang_auto_detect((*C.struct_whisper_context)(ctx), C.int(offset_ms), C.int(n_threads), (*C.float)(&probs[0]))); n < 0 {
|
||||||
|
return nil, ErrAutoDetectFailed
|
||||||
|
} else {
|
||||||
|
return probs, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Whisper_n_len() int {
|
||||||
|
return int(C.whisper_n_len((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Whisper_n_vocab() int {
|
||||||
|
return int(C.whisper_n_vocab((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Whisper_n_text_ctx() int {
|
||||||
|
return int(C.whisper_n_text_ctx((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Whisper_n_audio_ctx() int {
|
||||||
|
return int(C.whisper_n_audio_ctx((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *Context) Whisper_is_multilingual() int {
|
||||||
|
return int(C.whisper_is_multilingual((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The probabilities for the next token
|
||||||
|
//func (ctx *Whisper_context) Whisper_get_probs() []float32 {
|
||||||
|
// return (*[1 << 30]float32)(unsafe.Pointer(C.whisper_get_probs((*C.struct_whisper_context)(ctx))))[:ctx.Whisper_n_vocab()]
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Token Id -> String. Uses the vocabulary in the provided context
|
||||||
|
func (ctx *Context) Whisper_token_to_str(token Token) string {
|
||||||
|
return C.GoString(C.whisper_token_to_str((*C.struct_whisper_context)(ctx), C.whisper_token(token)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_eot() Token {
|
||||||
|
return Token(C.whisper_token_eot((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_sot() Token {
|
||||||
|
return Token(C.whisper_token_sot((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_prev() Token {
|
||||||
|
return Token(C.whisper_token_prev((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_solm() Token {
|
||||||
|
return Token(C.whisper_token_solm((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_not() Token {
|
||||||
|
return Token(C.whisper_token_not((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_beg() Token {
|
||||||
|
return Token(C.whisper_token_beg((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
func (ctx *Context) Whisper_token_lang(lang_id int) Token {
|
||||||
|
return Token(C.whisper_token_lang((*C.struct_whisper_context)(ctx), C.int(lang_id)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task tokens
|
||||||
|
func (ctx *Context) Whisper_token_translate() Token {
|
||||||
|
return Token(C.whisper_token_translate((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Task tokens
|
||||||
|
func (ctx *Context) Whisper_token_transcribe() Token {
|
||||||
|
return Token(C.whisper_token_transcribe((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance information
|
||||||
|
func (ctx *Context) Whisper_print_timings() {
|
||||||
|
C.whisper_print_timings((*C.struct_whisper_context)(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Performance information
|
||||||
|
func (ctx *Context) Whisper_reset_timings() {
|
||||||
|
C.whisper_reset_timings((*C.struct_whisper_context)(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print system information
|
||||||
|
func Whisper_print_system_info() string {
|
||||||
|
return C.GoString(C.whisper_print_system_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return default parameters for a strategy
|
||||||
|
func (ctx *Context) Whisper_full_default_params(strategy SamplingStrategy) Params {
|
||||||
|
// Get default parameters
|
||||||
|
return Params(C.whisper_full_default_params_cb((*C.struct_whisper_context)(ctx), C.enum_whisper_sampling_strategy(strategy)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text
|
||||||
|
// Uses the specified decoding strategy to obtain the text.
|
||||||
|
func (ctx *Context) Whisper_full(
|
||||||
|
params Params,
|
||||||
|
samples []float32,
|
||||||
|
encoderBeginCallback func() bool,
|
||||||
|
newSegmentCallback func(int),
|
||||||
|
progressCallback func(int),
|
||||||
|
) error {
|
||||||
|
registerEncoderBeginCallback(ctx, encoderBeginCallback)
|
||||||
|
registerNewSegmentCallback(ctx, newSegmentCallback)
|
||||||
|
registerProgressCallback(ctx, progressCallback)
|
||||||
|
defer registerEncoderBeginCallback(ctx, nil)
|
||||||
|
defer registerNewSegmentCallback(ctx, nil)
|
||||||
|
defer registerProgressCallback(ctx, nil)
|
||||||
|
if C.whisper_full((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples))) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the input audio in chunks and process each chunk separately using whisper_full()
|
||||||
|
// It seems this approach can offer some speedup in some cases.
|
||||||
|
// However, the transcription accuracy can be worse at the beginning and end of each chunk.
|
||||||
|
func (ctx *Context) Whisper_full_parallel(params Params, samples []float32, processors int, encoderBeginCallback func() bool, newSegmentCallback func(int)) error {
|
||||||
|
registerEncoderBeginCallback(ctx, encoderBeginCallback)
|
||||||
|
registerNewSegmentCallback(ctx, newSegmentCallback)
|
||||||
|
defer registerEncoderBeginCallback(ctx, nil)
|
||||||
|
defer registerNewSegmentCallback(ctx, nil)
|
||||||
|
|
||||||
|
if C.whisper_full_parallel((*C.struct_whisper_context)(ctx), (C.struct_whisper_full_params)(params), (*C.float)(&samples[0]), C.int(len(samples)), C.int(processors)) == 0 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return ErrConversionFailed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the id of the autodetected language, returns -1 if not found
|
||||||
|
// Added to whisper.cpp in
|
||||||
|
// https://github.com/ggerganov/whisper.cpp/commit/a1c1583cc7cd8b75222857afc936f0638c5683d6
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// "de" -> 2
|
||||||
|
// "german" -> 2
|
||||||
|
func (ctx *Context) Whisper_full_lang_id() int {
|
||||||
|
return int(C.whisper_full_lang_id((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of generated text segments.
|
||||||
|
// A segment can be a few words, a sentence, or even a paragraph.
|
||||||
|
func (ctx *Context) Whisper_full_n_segments() int {
|
||||||
|
return int(C.whisper_full_n_segments((*C.struct_whisper_context)(ctx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the start and end time of the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_segment_t0(segment int) int64 {
|
||||||
|
return int64(C.whisper_full_get_segment_t0((*C.struct_whisper_context)(ctx), C.int(segment)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the start and end time of the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_segment_t1(segment int) int64 {
|
||||||
|
return int64(C.whisper_full_get_segment_t1((*C.struct_whisper_context)(ctx), C.int(segment)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the text of the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_segment_text(segment int) string {
|
||||||
|
return C.GoString(C.whisper_full_get_segment_text((*C.struct_whisper_context)(ctx), C.int(segment)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get number of tokens in the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_n_tokens(segment int) int {
|
||||||
|
return int(C.whisper_full_n_tokens((*C.struct_whisper_context)(ctx), C.int(segment)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the token text of the specified token index in the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_token_text(segment int, token int) string {
|
||||||
|
return C.GoString(C.whisper_full_get_token_text((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the token of the specified token index in the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_token_id(segment int, token int) Token {
|
||||||
|
return Token(C.whisper_full_get_token_id((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get token data for the specified token in the specified segment.
|
||||||
|
// This contains probabilities, timestamps, etc.
|
||||||
|
func (ctx *Context) Whisper_full_get_token_data(segment int, token int) TokenData {
|
||||||
|
return TokenData(C.whisper_full_get_token_data((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the probability of the specified token in the specified segment.
|
||||||
|
func (ctx *Context) Whisper_full_get_token_p(segment int, token int) float32 {
|
||||||
|
return float32(C.whisper_full_get_token_p((*C.struct_whisper_context)(ctx), C.int(segment), C.int(token)))
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CALLBACKS
|
||||||
|
|
||||||
|
var (
|
||||||
|
cbNewSegment = make(map[unsafe.Pointer]func(int))
|
||||||
|
cbProgress = make(map[unsafe.Pointer]func(int))
|
||||||
|
cbEncoderBegin = make(map[unsafe.Pointer]func() bool)
|
||||||
|
)
|
||||||
|
|
||||||
|
func registerNewSegmentCallback(ctx *Context, fn func(int)) {
|
||||||
|
if fn == nil {
|
||||||
|
delete(cbNewSegment, unsafe.Pointer(ctx))
|
||||||
|
} else {
|
||||||
|
cbNewSegment[unsafe.Pointer(ctx)] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerProgressCallback(ctx *Context, fn func(int)) {
|
||||||
|
if fn == nil {
|
||||||
|
delete(cbProgress, unsafe.Pointer(ctx))
|
||||||
|
} else {
|
||||||
|
cbProgress[unsafe.Pointer(ctx)] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerEncoderBeginCallback(ctx *Context, fn func() bool) {
|
||||||
|
if fn == nil {
|
||||||
|
delete(cbEncoderBegin, unsafe.Pointer(ctx))
|
||||||
|
} else {
|
||||||
|
cbEncoderBegin[unsafe.Pointer(ctx)] = fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export callNewSegment
|
||||||
|
func callNewSegment(user_data unsafe.Pointer, new C.int) {
|
||||||
|
if fn, ok := cbNewSegment[user_data]; ok {
|
||||||
|
fn(int(new))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export callProgress
|
||||||
|
func callProgress(user_data unsafe.Pointer, progress C.int) {
|
||||||
|
if fn, ok := cbProgress[user_data]; ok {
|
||||||
|
fn(int(progress))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export callEncoderBegin
|
||||||
|
func callEncoderBegin(user_data unsafe.Pointer) C.bool {
|
||||||
|
if fn, ok := cbEncoderBegin[user_data]; ok {
|
||||||
|
if fn() {
|
||||||
|
return C.bool(true)
|
||||||
|
} else {
|
||||||
|
return C.bool(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TokenData) T0() int64 {
|
||||||
|
return int64(t.t0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TokenData) T1() int64 {
|
||||||
|
return int64(t.t1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TokenData) Id() Token {
|
||||||
|
return Token(t.id)
|
||||||
|
}
|
||||||
113
bindings/go/whisper_test.go
Normal file
113
bindings/go/whisper_test.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package whisper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
// Packages
|
||||||
|
whisper "github.com/ggerganov/whisper.cpp/bindings/go"
|
||||||
|
wav "github.com/go-audio/wav"
|
||||||
|
assert "github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ModelPath = "models/ggml-small.en.bin"
|
||||||
|
SamplePath = "samples/jfk.wav"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_Whisper_000(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
if _, err := os.Stat(ModelPath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, model not found:", ModelPath)
|
||||||
|
}
|
||||||
|
ctx := whisper.Whisper_init(ModelPath)
|
||||||
|
assert.NotNil(ctx)
|
||||||
|
ctx.Whisper_free()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Whisper_001(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
if _, err := os.Stat(ModelPath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, model not found:", ModelPath)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(SamplePath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, sample not found:", SamplePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open samples
|
||||||
|
fh, err := os.Open(SamplePath)
|
||||||
|
assert.NoError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Read samples
|
||||||
|
d := wav.NewDecoder(fh)
|
||||||
|
buf, err := d.FullPCMBuffer()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// Run whisper
|
||||||
|
ctx := whisper.Whisper_init(ModelPath)
|
||||||
|
assert.NotNil(ctx)
|
||||||
|
defer ctx.Whisper_free()
|
||||||
|
params := ctx.Whisper_full_default_params(whisper.SAMPLING_GREEDY)
|
||||||
|
data := buf.AsFloat32Buffer().Data
|
||||||
|
err = ctx.Whisper_full(params, data, nil, nil, nil)
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// Print out tokens
|
||||||
|
num_segments := ctx.Whisper_full_n_segments()
|
||||||
|
assert.GreaterOrEqual(num_segments, 1)
|
||||||
|
for i := 0; i < num_segments; i++ {
|
||||||
|
str := ctx.Whisper_full_get_segment_text(i)
|
||||||
|
assert.NotEmpty(str)
|
||||||
|
t0 := time.Duration(ctx.Whisper_full_get_segment_t0(i)) * time.Millisecond
|
||||||
|
t1 := time.Duration(ctx.Whisper_full_get_segment_t1(i)) * time.Millisecond
|
||||||
|
t.Logf("[%6s->%-6s] %q", t0, t1, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Whisper_002(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
for i := 0; i < whisper.Whisper_lang_max_id(); i++ {
|
||||||
|
str := whisper.Whisper_lang_str(i)
|
||||||
|
assert.NotEmpty(str)
|
||||||
|
t.Log(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Whisper_003(t *testing.T) {
|
||||||
|
threads := runtime.NumCPU()
|
||||||
|
assert := assert.New(t)
|
||||||
|
if _, err := os.Stat(ModelPath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, model not found:", ModelPath)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(SamplePath); os.IsNotExist(err) {
|
||||||
|
t.Skip("Skipping test, sample not found:", SamplePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open samples
|
||||||
|
fh, err := os.Open(SamplePath)
|
||||||
|
assert.NoError(err)
|
||||||
|
defer fh.Close()
|
||||||
|
|
||||||
|
// Read samples
|
||||||
|
d := wav.NewDecoder(fh)
|
||||||
|
buf, err := d.FullPCMBuffer()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
// Make the model
|
||||||
|
ctx := whisper.Whisper_init(ModelPath)
|
||||||
|
assert.NotNil(ctx)
|
||||||
|
defer ctx.Whisper_free()
|
||||||
|
|
||||||
|
// Get MEL
|
||||||
|
assert.NoError(ctx.Whisper_pcm_to_mel(buf.AsFloat32Buffer().Data, threads))
|
||||||
|
|
||||||
|
// Get Languages
|
||||||
|
languages, err := ctx.Whisper_lang_auto_detect(0, threads)
|
||||||
|
assert.NoError(err)
|
||||||
|
for i, p := range languages {
|
||||||
|
t.Logf("%s: %f", whisper.Whisper_lang_str(i), p)
|
||||||
|
}
|
||||||
|
}
|
||||||
87
bindings/java/README.md
Normal file
87
bindings/java/README.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Java JNI bindings for Whisper
|
||||||
|
|
||||||
|
This package provides Java JNI bindings for whisper.cpp. They have been tested on:
|
||||||
|
|
||||||
|
* <strike>Darwin (OS X) 12.6 on x64_64</strike>
|
||||||
|
* Ubuntu on x86_64
|
||||||
|
* Windows on x86_64
|
||||||
|
|
||||||
|
The "low level" bindings are in `WhisperCppJnaLibrary`. The most simple usage is as follows:
|
||||||
|
|
||||||
|
JNA will attempt to load the `whispercpp` shared library from:
|
||||||
|
|
||||||
|
- jna.library.path
|
||||||
|
- jna.platform.library
|
||||||
|
- ~/Library/Frameworks
|
||||||
|
- /Library/Frameworks
|
||||||
|
- /System/Library/Frameworks
|
||||||
|
- classpath
|
||||||
|
|
||||||
|
```java
|
||||||
|
import io.github.ggerganov.whispercpp.WhisperCpp;
|
||||||
|
|
||||||
|
public class Example {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
WhisperCpp whisper = new WhisperCpp();
|
||||||
|
try {
|
||||||
|
// By default, models are loaded from ~/.cache/whisper/ and are usually named "ggml-${name}.bin"
|
||||||
|
// or you can provide the absolute path to the model file.
|
||||||
|
whisper.initContext("../ggml-base.en.bin");
|
||||||
|
WhisperFullParams.ByValue whisperParams = whisper.getFullDefaultParams(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH);
|
||||||
|
|
||||||
|
// custom configuration if required
|
||||||
|
//whisperParams.n_threads = 8;
|
||||||
|
whisperParams.temperature = 0.0f;
|
||||||
|
whisperParams.temperature_inc = 0.2f;
|
||||||
|
//whisperParams.language = "en";
|
||||||
|
|
||||||
|
float[] samples = readAudio(); // divide each value by 32767.0f
|
||||||
|
List<WhisperSegment> whisperSegmentList = whisper.fullTranscribeWithTime(whisperParams, samples);
|
||||||
|
|
||||||
|
for (WhisperSegment whisperSegment : whisperSegmentList) {
|
||||||
|
|
||||||
|
long start = whisperSegment.getStart();
|
||||||
|
long end = whisperSegment.getEnd();
|
||||||
|
|
||||||
|
String text = whisperSegment.getSentence();
|
||||||
|
|
||||||
|
System.out.println("start: "+start);
|
||||||
|
System.out.println("end: "+end);
|
||||||
|
System.out.println("text: "+text);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
whisper.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building & Testing
|
||||||
|
|
||||||
|
In order to build, you need to have the JDK 8 or higher installed. Run the tests with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/ggml-org/whisper.cpp.git
|
||||||
|
cd whisper.cpp/bindings/java
|
||||||
|
|
||||||
|
./gradlew build
|
||||||
|
```
|
||||||
|
|
||||||
|
You need to have the `whisper` library in your [JNA library path](https://java-native-access.github.io/jna/4.2.1/com/sun/jna/NativeLibrary.html). On Windows the dll is included in the jar and you can update it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
copy /y ..\..\build\bin\Release\whisper.dll build\generated\resources\main\win32-x86-64\whisper.dll
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
The license for the Java bindings is the same as the license for the rest of the whisper.cpp project, which is the MIT License. See the `LICENSE` file for more details.
|
||||||
|
|
||||||
159
bindings/java/build.gradle
Normal file
159
bindings/java/build.gradle
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'java-library'
|
||||||
|
id 'maven-publish'
|
||||||
|
id 'signing'
|
||||||
|
}
|
||||||
|
|
||||||
|
archivesBaseName = 'whispercpp'
|
||||||
|
group = 'io.github.ggerganov'
|
||||||
|
version = '1.4.0'
|
||||||
|
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
targetCompatibility = 1.8
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
resources {
|
||||||
|
srcDirs = ['src/main/resources', 'build/generated/resources/main']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
test {
|
||||||
|
runtimeClasspath += files('build/generated/resources/main')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyLibwhisperDynlib', Copy) {
|
||||||
|
from '../../build/src'
|
||||||
|
include 'libwhisper.dylib'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyLibwhisperSo', Copy) {
|
||||||
|
from '../../build/src'
|
||||||
|
include 'libwhisper.so'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyWhisperDLL', Copy) {
|
||||||
|
from '../../build/bin/Release'
|
||||||
|
include 'whisper.dll'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyGGML_BASE_DLL', Copy) {
|
||||||
|
from '../../build/bin/Release'
|
||||||
|
include 'ggml-base.dll'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyGGML_DLL', Copy) {
|
||||||
|
from '../../build/bin/Release'
|
||||||
|
include 'ggml.dll'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyGGML_CPU_DLL', Copy) {
|
||||||
|
from '../../build/bin/Release'
|
||||||
|
include 'ggml-cpu.dll'
|
||||||
|
into 'build/generated/resources/main'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('copyLibs') {
|
||||||
|
dependsOn copyLibwhisperDynlib, copyLibwhisperSo, copyWhisperDLL, copyGGML_BASE_DLL, copyGGML_DLL, copyGGML_CPU_DLL
|
||||||
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
systemProperty 'jna.library.path', project.file('build/generated/resources/main').absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesJar() {
|
||||||
|
dependsOn copyLibs
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
dependsOn copyLibs
|
||||||
|
exclude '**/whisper_java.exp', '**/whisper_java.lib'
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options.addStringOption('Xdoclint:none', '-quiet')
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(Test) {
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
test.dependsOn copyLibs
|
||||||
|
processResources.dependsOn copyLibs
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "net.java.dev.jna:jna:5.13.0"
|
||||||
|
testImplementation "org.junit.jupiter:junit-jupiter:5.9.2"
|
||||||
|
testImplementation "org.assertj:assertj-core:3.24.2"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
mavenJava(MavenPublication) {
|
||||||
|
artifactId = 'whispercpp'
|
||||||
|
from components.java
|
||||||
|
pom {
|
||||||
|
name = 'whispercpp'
|
||||||
|
description = "Java JNA bindings for OpenAI's Whisper model, implemented in C/C++"
|
||||||
|
url = 'https://github.com/ggerganov/whisper.cpp'
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'MIT licence'
|
||||||
|
url = 'https://raw.githubusercontent.com/ggerganov/whisper.cpp/master/LICENSE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
developers {
|
||||||
|
developer {
|
||||||
|
id = 'ggerganov'
|
||||||
|
name = 'Georgi Gerganov'
|
||||||
|
email = 'ggerganov@gmail.com'
|
||||||
|
}
|
||||||
|
developer {
|
||||||
|
id = 'nalbion'
|
||||||
|
name = 'Nicholas Albion'
|
||||||
|
email = 'nalbion@yahoo.com'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scm {
|
||||||
|
connection = 'scm:git:git://github.com/ggerganov/whisper.cpp.git'
|
||||||
|
url = 'https://github.com/ggerganov/whisper.cpp'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
def releasesRepoUrl = 'https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/'
|
||||||
|
def snapshotsRepoUrl = 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
|
||||||
|
url = version.endsWith('-SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
|
||||||
|
credentials {
|
||||||
|
username = System.getenv("MAVEN_USERNAME")
|
||||||
|
password = System.getenv("MAVEN_PASSWORD")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signing {
|
||||||
|
def signingKey = System.getenv("PGP_SECRET")
|
||||||
|
def signingPassword = System.getenv("PGP_PASSPHRASE")
|
||||||
|
useInMemoryPgpKeys(signingKey, signingPassword)
|
||||||
|
sign publishing.publications.mavenJava
|
||||||
|
}
|
||||||
6
bindings/java/gradle.properties
Normal file
6
bindings/java/gradle.properties
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
|
system.include.dir=/usr/include
|
||||||
|
#system.local.include.dir=../../include
|
||||||
|
system.local.include.dir=./build/generated/sources/headers/java/main
|
||||||
|
jni.include.dir=/usr/lib/jvm/java-8-openjdk-amd64/include/
|
||||||
|
jni.lib.dir=/usr/lib/jvm/java-8-openjdk-amd64/lib/
|
||||||
BIN
bindings/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
bindings/java/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
6
bindings/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
6
bindings/java/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
244
bindings/java/gradlew
vendored
Executable file
244
bindings/java/gradlew
vendored
Executable file
@@ -0,0 +1,244 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
92
bindings/java/gradlew.bat
vendored
Normal file
92
bindings/java/gradlew.bat
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
|
echo.
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
echo location of your Java installation.
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
1
bindings/java/settings.gradle
Normal file
1
bindings/java/settings.gradle
Normal file
@@ -0,0 +1 @@
|
|||||||
|
rootProject.name = "whispercpp"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.github.ggerganov.whispercpp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Presets for alignment heads in DTW token timestamps
|
||||||
|
*/
|
||||||
|
public class WhisperConstants {
|
||||||
|
// Alignment heads presets
|
||||||
|
public static final int WHISPER_AHEADS_NONE = 0;
|
||||||
|
public static final int WHISPER_AHEADS_TINY_EN = 1;
|
||||||
|
public static final int WHISPER_AHEADS_TINY = 2;
|
||||||
|
public static final int WHISPER_AHEADS_BASE_EN = 3;
|
||||||
|
public static final int WHISPER_AHEADS_BASE = 4;
|
||||||
|
public static final int WHISPER_AHEADS_SMALL_EN = 5;
|
||||||
|
public static final int WHISPER_AHEADS_SMALL = 6;
|
||||||
|
public static final int WHISPER_AHEADS_MEDIUM_EN = 7;
|
||||||
|
public static final int WHISPER_AHEADS_MEDIUM = 8;
|
||||||
|
public static final int WHISPER_AHEADS_LARGE_V1 = 9;
|
||||||
|
public static final int WHISPER_AHEADS_LARGE_V2 = 10;
|
||||||
|
public static final int WHISPER_AHEADS_LARGE_V3 = 11;
|
||||||
|
public static final int WHISPER_AHEADS_LARGE_V3_TURBO = 12;
|
||||||
|
public static final int WHISPER_AHEADS_CUSTOM = 13;
|
||||||
|
public static final int WHISPER_AHEADS_N_TOP_MOST = 14;
|
||||||
|
public static final int WHISPER_AHEADS_COUNT = 15;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package io.github.ggerganov.whispercpp;
|
||||||
|
|
||||||
|
import com.sun.jna.NativeLong;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.ptr.PointerByReference;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.ggml.GgmlType;
|
||||||
|
import io.github.ggerganov.whispercpp.WhisperModel;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperContextParams;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WhisperContext extends Structure {
|
||||||
|
public NativeLong t_load_us;
|
||||||
|
public NativeLong t_start_us;
|
||||||
|
|
||||||
|
/** weight type (FP32 / FP16 / QX) */
|
||||||
|
public GgmlType wtype = GgmlType.GGML_TYPE_F16;
|
||||||
|
/** intermediate type (FP32 or FP16) */
|
||||||
|
public GgmlType itype = GgmlType.GGML_TYPE_F16;
|
||||||
|
|
||||||
|
public WhisperContextParams.ByValue params;
|
||||||
|
|
||||||
|
public Pointer model;
|
||||||
|
public Pointer vocab;
|
||||||
|
public Pointer state;
|
||||||
|
|
||||||
|
/** populated by whisper_init_from_file_with_params() */
|
||||||
|
public Pointer path_model;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return List.of("t_load_us", "t_start_us", "wtype", "itype",
|
||||||
|
"params", "model", "vocab", "state", "path_model");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
package io.github.ggerganov.whispercpp;
|
||||||
|
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.bean.WhisperSegment;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperContextParams;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperFullParams;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperSamplingStrategy;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before calling most methods, you must call `initContext(modelPath)` to initialise the `ctx` Pointer.
|
||||||
|
*/
|
||||||
|
public class WhisperCpp implements AutoCloseable {
|
||||||
|
private WhisperCppJnaLibrary lib = WhisperCppJnaLibrary.instance;
|
||||||
|
private Pointer ctx = null;
|
||||||
|
private Pointer paramsPointer = null;
|
||||||
|
private Pointer greedyParamsPointer = null;
|
||||||
|
private Pointer beamParamsPointer = null;
|
||||||
|
|
||||||
|
public File modelDir() {
|
||||||
|
String modelDirPath = System.getenv("XDG_CACHE_HOME");
|
||||||
|
if (modelDirPath == null) {
|
||||||
|
modelDirPath = System.getProperty("user.home") + "/.cache";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new File(modelDirPath, "whisper");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param modelPath - absolute path, or just the name (eg: "base", "base-en" or "base.en")
|
||||||
|
*/
|
||||||
|
public void initContext(String modelPath) throws FileNotFoundException {
|
||||||
|
initContextImpl(modelPath, getContextDefaultParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param modelPath - absolute path, or just the name (eg: "base", "base-en" or "base.en")
|
||||||
|
* @param params - params to use when initialising the context
|
||||||
|
*/
|
||||||
|
public void initContext(String modelPath, WhisperContextParams.ByValue params) throws FileNotFoundException {
|
||||||
|
initContextImpl(modelPath, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initContextImpl(String modelPath, WhisperContextParams.ByValue params) throws FileNotFoundException {
|
||||||
|
if (ctx != null) {
|
||||||
|
lib.whisper_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!modelPath.contains("/") && !modelPath.contains("\\")) {
|
||||||
|
if (!modelPath.endsWith(".bin")) {
|
||||||
|
modelPath = "ggml-" + modelPath.replace("-", ".") + ".bin";
|
||||||
|
}
|
||||||
|
|
||||||
|
modelPath = new File(modelDir(), modelPath).getAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = lib.whisper_init_from_file_with_params(modelPath, params);
|
||||||
|
|
||||||
|
if (ctx == null) {
|
||||||
|
throw new FileNotFoundException(modelPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default params which can be used with `whisper_init_from_file_with_params()` etc.
|
||||||
|
* Returns a ByValue instance to ensure proper parameter passing to native code.
|
||||||
|
*/
|
||||||
|
public WhisperContextParams.ByValue getContextDefaultParams() {
|
||||||
|
WhisperContextParams.ByValue valueParams = new WhisperContextParams.ByValue(
|
||||||
|
lib.whisper_context_default_params_by_ref());
|
||||||
|
valueParams.read();
|
||||||
|
return valueParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default params which can be used with `whisper_full()` etc.
|
||||||
|
* Because this function allocates memory for the params, the caller must call either:
|
||||||
|
* - call `whisper_free_params()`
|
||||||
|
* - `Native.free(Pointer.nativeValue(pointer));`
|
||||||
|
*
|
||||||
|
* @param strategy - GREEDY
|
||||||
|
*/
|
||||||
|
public WhisperFullParams.ByValue getFullDefaultParams(WhisperSamplingStrategy strategy) {
|
||||||
|
Pointer pointer;
|
||||||
|
|
||||||
|
// whisper_full_default_params_by_ref allocates memory which we need to delete, so only create max 1 pointer for each strategy.
|
||||||
|
if (strategy == WhisperSamplingStrategy.WHISPER_SAMPLING_GREEDY) {
|
||||||
|
if (greedyParamsPointer == null) {
|
||||||
|
greedyParamsPointer = lib.whisper_full_default_params_by_ref(strategy.ordinal());
|
||||||
|
}
|
||||||
|
pointer = greedyParamsPointer;
|
||||||
|
} else {
|
||||||
|
if (beamParamsPointer == null) {
|
||||||
|
beamParamsPointer = lib.whisper_full_default_params_by_ref(strategy.ordinal());
|
||||||
|
}
|
||||||
|
pointer = beamParamsPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
WhisperFullParams.ByValue params = new WhisperFullParams.ByValue(pointer);
|
||||||
|
params.read();
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
freeContext();
|
||||||
|
freeParams();
|
||||||
|
System.out.println("Whisper closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void freeContext() {
|
||||||
|
if (ctx != null) {
|
||||||
|
lib.whisper_free(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void freeParams() {
|
||||||
|
if (paramsPointer != null) {
|
||||||
|
Native.free(Pointer.nativeValue(paramsPointer));
|
||||||
|
paramsPointer = null;
|
||||||
|
}
|
||||||
|
if (greedyParamsPointer != null) {
|
||||||
|
Native.free(Pointer.nativeValue(greedyParamsPointer));
|
||||||
|
greedyParamsPointer = null;
|
||||||
|
}
|
||||||
|
if (beamParamsPointer != null) {
|
||||||
|
Native.free(Pointer.nativeValue(beamParamsPointer));
|
||||||
|
beamParamsPointer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text.
|
||||||
|
* Not thread safe for same context
|
||||||
|
* Uses the specified decoding strategy to obtain the text.
|
||||||
|
*/
|
||||||
|
public String fullTranscribe(WhisperFullParams.ByValue whisperParams, float[] audioData) throws IOException {
|
||||||
|
if (ctx == null) {
|
||||||
|
throw new IllegalStateException("Model not initialised");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
WhisperFullParams.ByValue valueParams = new WhisperFullParams.ByValue(
|
||||||
|
lib.whisper_full_default_params_by_ref(WhisperSamplingStrategy.WHISPER_SAMPLING_BEAM_SEARCH.ordinal()));
|
||||||
|
valueParams.read();
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (lib.whisper_full(ctx, whisperParams, audioData, audioData.length) != 0) {
|
||||||
|
throw new IOException("Failed to process audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
int nSegments = lib.whisper_full_n_segments(ctx);
|
||||||
|
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < nSegments; i++) {
|
||||||
|
String text = lib.whisper_full_get_segment_text(ctx, i);
|
||||||
|
System.out.println("Segment:" + text);
|
||||||
|
str.append(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full transcribe with time list.
|
||||||
|
*
|
||||||
|
* @param whisperParams the whisper params
|
||||||
|
* @param audioData the audio data
|
||||||
|
* @return the list
|
||||||
|
* @throws IOException the io exception
|
||||||
|
*/
|
||||||
|
public List<WhisperSegment> fullTranscribeWithTime(WhisperFullParams.ByValue whisperParams, float[] audioData) throws IOException {
|
||||||
|
if (ctx == null) {
|
||||||
|
throw new IllegalStateException("Model not initialised");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lib.whisper_full(ctx, whisperParams, audioData, audioData.length) != 0) {
|
||||||
|
throw new IOException("Failed to process audio");
|
||||||
|
}
|
||||||
|
|
||||||
|
int nSegments = lib.whisper_full_n_segments(ctx);
|
||||||
|
List<WhisperSegment> segments= new ArrayList<>(nSegments);
|
||||||
|
|
||||||
|
for (int i = 0; i < nSegments; i++) {
|
||||||
|
long t0 = lib.whisper_full_get_segment_t0(ctx, i);
|
||||||
|
String text = lib.whisper_full_get_segment_text(ctx, i);
|
||||||
|
long t1 = lib.whisper_full_get_segment_t1(ctx, i);
|
||||||
|
segments.add(new WhisperSegment(t0,t1,text));
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public int getTextSegmentCount(Pointer ctx) {
|
||||||
|
// return lib.whisper_full_n_segments(ctx);
|
||||||
|
// }
|
||||||
|
// public String getTextSegment(Pointer ctx, int index) {
|
||||||
|
// return lib.whisper_full_get_segment_text(ctx, index);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public String getSystemInfo() {
|
||||||
|
return lib.whisper_print_system_info();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int benchMemcpy(int nthread) {
|
||||||
|
return lib.whisper_bench_memcpy(nthread);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int benchGgmlMulMat(int nthread) {
|
||||||
|
return lib.whisper_bench_ggml_mul_mat(nthread);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
package io.github.ggerganov.whispercpp;
|
||||||
|
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperModelLoader;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperTokenData;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperContextParams;
|
||||||
|
import io.github.ggerganov.whispercpp.params.WhisperFullParams;
|
||||||
|
|
||||||
|
public interface WhisperCppJnaLibrary extends Library {
|
||||||
|
|
||||||
|
WhisperCppJnaLibrary instance = Native.load("whisper", WhisperCppJnaLibrary.class);
|
||||||
|
|
||||||
|
String whisper_print_system_info();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Allocate (almost) all memory needed for the model by loading from a file.
|
||||||
|
*
|
||||||
|
* @param path_model Path to the model file
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_from_file(String path_model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default params which can be used with `whisper_init_from_file_with_params()` etc.
|
||||||
|
* Because this function allocates memory for the params, the caller must call either:
|
||||||
|
* - call `whisper_free_context_params()`
|
||||||
|
* - `Native.free(Pointer.nativeValue(pointer));`
|
||||||
|
*/
|
||||||
|
Pointer whisper_context_default_params_by_ref();
|
||||||
|
|
||||||
|
void whisper_free_context_params(Pointer params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model by loading from a file.
|
||||||
|
*
|
||||||
|
* @param path_model Path to the model file
|
||||||
|
* @param params Pointer to whisper_context_params
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_from_file_with_params(String path_model, WhisperContextParams.ByValue params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model by loading from a buffer.
|
||||||
|
*
|
||||||
|
* @param buffer Model buffer
|
||||||
|
* @param buffer_size Size of the model buffer
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_from_buffer(Pointer buffer, int buffer_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model using a model loader.
|
||||||
|
*
|
||||||
|
* @param loader Model loader
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init(WhisperModelLoader loader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model by loading from a file without allocating the state.
|
||||||
|
*
|
||||||
|
* @param path_model Path to the model file
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_from_file_no_state(String path_model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model by loading from a buffer without allocating the state.
|
||||||
|
*
|
||||||
|
* @param buffer Model buffer
|
||||||
|
* @param buffer_size Size of the model buffer
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_from_buffer_no_state(Pointer buffer, int buffer_size);
|
||||||
|
|
||||||
|
// Pointer whisper_init_from_buffer_no_state(Pointer buffer, long buffer_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate (almost) all memory needed for the model using a model loader without allocating the state.
|
||||||
|
*
|
||||||
|
* @param loader Model loader
|
||||||
|
* @return Whisper context on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_no_state(WhisperModelLoader loader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate memory for the Whisper state.
|
||||||
|
*
|
||||||
|
* @param ctx Whisper context
|
||||||
|
* @return Whisper state on success, null on failure
|
||||||
|
*/
|
||||||
|
Pointer whisper_init_state(Pointer ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free all allocated memory associated with the Whisper context.
|
||||||
|
*
|
||||||
|
* @param ctx Whisper context
|
||||||
|
*/
|
||||||
|
void whisper_free(Pointer ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free all allocated memory associated with the Whisper state.
|
||||||
|
*
|
||||||
|
* @param state Whisper state
|
||||||
|
*/
|
||||||
|
void whisper_free_state(Pointer state);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert RAW PCM audio to log mel spectrogram.
|
||||||
|
* The resulting spectrogram is stored inside the default state of the provided whisper context.
|
||||||
|
*
|
||||||
|
* @param ctx - Pointer to a WhisperContext
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int whisper_pcm_to_mel(Pointer ctx, final float[] samples, int n_samples, int n_threads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ctx Pointer to a WhisperContext
|
||||||
|
* @param state Pointer to WhisperState
|
||||||
|
* @param n_samples
|
||||||
|
* @param n_threads
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int whisper_pcm_to_mel_with_state(Pointer ctx, Pointer state, final float[] samples, int n_samples, int n_threads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This can be used to set a custom log mel spectrogram inside the default state of the provided whisper context.
|
||||||
|
* Use this instead of whisper_pcm_to_mel() if you want to provide your own log mel spectrogram.
|
||||||
|
* n_mel must be 80
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int whisper_set_mel(Pointer ctx, final float[] data, int n_len, int n_mel);
|
||||||
|
int whisper_set_mel_with_state(Pointer ctx, Pointer state, final float[] data, int n_len, int n_mel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the Whisper encoder on the log mel spectrogram stored inside the default state in the provided whisper context.
|
||||||
|
* Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first.
|
||||||
|
* Offset can be used to specify the offset of the first frame in the spectrogram.
|
||||||
|
* @return 0 on success
|
||||||
|
*/
|
||||||
|
int whisper_encode(Pointer ctx, int offset, int n_threads);
|
||||||
|
|
||||||
|
int whisper_encode_with_state(Pointer ctx, Pointer state, int offset, int n_threads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the Whisper decoder to obtain the logits and probabilities for the next token.
|
||||||
|
* Make sure to call whisper_encode() first.
|
||||||
|
* tokens + n_tokens is the provided context for the decoder.
|
||||||
|
* n_past is the number of tokens to use from previous decoder calls.
|
||||||
|
* Returns 0 on success
|
||||||
|
* TODO: add support for multiple decoders
|
||||||
|
*/
|
||||||
|
int whisper_decode(Pointer ctx, Pointer tokens, int n_tokens, int n_past, int n_threads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ctx
|
||||||
|
* @param state
|
||||||
|
* @param tokens Pointer to int tokens
|
||||||
|
* @param n_tokens
|
||||||
|
* @param n_past
|
||||||
|
* @param n_threads
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
int whisper_decode_with_state(Pointer ctx, Pointer state, Pointer tokens, int n_tokens, int n_past, int n_threads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the provided text into tokens.
|
||||||
|
* The tokens pointer must be large enough to hold the resulting tokens.
|
||||||
|
* Returns the number of tokens on success, no more than n_max_tokens
|
||||||
|
* Returns -1 on failure
|
||||||
|
* TODO: not sure if correct
|
||||||
|
*/
|
||||||
|
int whisper_tokenize(Pointer ctx, String text, Pointer tokens, int n_max_tokens);
|
||||||
|
|
||||||
|
/** Largest language id (i.e. number of available languages - 1) */
|
||||||
|
int whisper_lang_max_id();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id of the specified language, returns -1 if not found.
|
||||||
|
* Examples:
|
||||||
|
* "de" -> 2
|
||||||
|
* "german" -> 2
|
||||||
|
*/
|
||||||
|
int whisper_lang_id(String lang);
|
||||||
|
|
||||||
|
/** @return the short string of the specified language id (e.g. 2 -> "de"), returns nullptr if not found */
|
||||||
|
String whisper_lang_str(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use mel data at offset_ms to try and auto-detect the spoken language.
|
||||||
|
* Make sure to call whisper_pcm_to_mel() or whisper_set_mel() first
|
||||||
|
* Returns the top language id or negative on failure
|
||||||
|
* If not null, fills the lang_probs array with the probabilities of all languages
|
||||||
|
* The array must be whisper_lang_max_id() + 1 in size
|
||||||
|
*
|
||||||
|
* ref: https://github.com/openai/whisper/blob/main/whisper/decoding.py#L18-L69
|
||||||
|
*/
|
||||||
|
int whisper_lang_auto_detect(Pointer ctx, int offset_ms, int n_threads, float[] lang_probs);
|
||||||
|
|
||||||
|
int whisper_lang_auto_detect_with_state(Pointer ctx, Pointer state, int offset_ms, int n_threads, float[] lang_probs);
|
||||||
|
|
||||||
|
int whisper_n_len (Pointer ctx); // mel length
|
||||||
|
int whisper_n_len_from_state(Pointer state); // mel length
|
||||||
|
int whisper_n_vocab (Pointer ctx);
|
||||||
|
int whisper_n_text_ctx (Pointer ctx);
|
||||||
|
int whisper_n_audio_ctx (Pointer ctx);
|
||||||
|
int whisper_is_multilingual (Pointer ctx);
|
||||||
|
|
||||||
|
int whisper_model_n_vocab (Pointer ctx);
|
||||||
|
int whisper_model_n_audio_ctx (Pointer ctx);
|
||||||
|
int whisper_model_n_audio_state(Pointer ctx);
|
||||||
|
int whisper_model_n_audio_head (Pointer ctx);
|
||||||
|
int whisper_model_n_audio_layer(Pointer ctx);
|
||||||
|
int whisper_model_n_text_ctx (Pointer ctx);
|
||||||
|
int whisper_model_n_text_state (Pointer ctx);
|
||||||
|
int whisper_model_n_text_head (Pointer ctx);
|
||||||
|
int whisper_model_n_text_layer (Pointer ctx);
|
||||||
|
int whisper_model_n_mels (Pointer ctx);
|
||||||
|
int whisper_model_ftype (Pointer ctx);
|
||||||
|
int whisper_model_type (Pointer ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Token logits obtained from the last call to whisper_decode().
|
||||||
|
* The logits for the last token are stored in the last row
|
||||||
|
* Rows: n_tokens
|
||||||
|
* Cols: n_vocab
|
||||||
|
*/
|
||||||
|
float[] whisper_get_logits (Pointer ctx);
|
||||||
|
float[] whisper_get_logits_from_state(Pointer state);
|
||||||
|
|
||||||
|
// Token Id -> String. Uses the vocabulary in the provided context
|
||||||
|
String whisper_token_to_str(Pointer ctx, int token);
|
||||||
|
String whisper_model_type_readable(Pointer ctx);
|
||||||
|
|
||||||
|
// Special tokens
|
||||||
|
int whisper_token_eot (Pointer ctx);
|
||||||
|
int whisper_token_sot (Pointer ctx);
|
||||||
|
int whisper_token_prev(Pointer ctx);
|
||||||
|
int whisper_token_solm(Pointer ctx);
|
||||||
|
int whisper_token_not (Pointer ctx);
|
||||||
|
int whisper_token_beg (Pointer ctx);
|
||||||
|
int whisper_token_lang(Pointer ctx, int lang_id);
|
||||||
|
|
||||||
|
// Task tokens
|
||||||
|
int whisper_token_translate (Pointer ctx);
|
||||||
|
int whisper_token_transcribe(Pointer ctx);
|
||||||
|
|
||||||
|
// Performance information from the default state.
|
||||||
|
void whisper_print_timings(Pointer ctx);
|
||||||
|
void whisper_reset_timings(Pointer ctx);
|
||||||
|
|
||||||
|
// Note: Even if `whisper_full_params is stripped back to just 4 ints, JNA throws "Invalid memory access"
|
||||||
|
// when `whisper_full_default_params()` tries to return a struct.
|
||||||
|
// WhisperFullParams whisper_full_default_params(int strategy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides default params which can be used with `whisper_full()` etc.
|
||||||
|
* Because this function allocates memory for the params, the caller must call either:
|
||||||
|
* - call `whisper_free_params()`
|
||||||
|
* - `Native.free(Pointer.nativeValue(pointer));`
|
||||||
|
*
|
||||||
|
* @param strategy - WhisperSamplingStrategy.value
|
||||||
|
*/
|
||||||
|
Pointer whisper_full_default_params_by_ref(int strategy);
|
||||||
|
|
||||||
|
void whisper_free_params(Pointer params);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the entire model: PCM -> log mel spectrogram -> encoder -> decoder -> text
|
||||||
|
* Not thread safe for same context
|
||||||
|
* Uses the specified decoding strategy to obtain the text.
|
||||||
|
*/
|
||||||
|
int whisper_full(Pointer ctx, WhisperFullParams.ByValue params, final float[] samples, int n_samples);
|
||||||
|
|
||||||
|
public int whisper_full_with_state(Pointer ctx, Pointer state, WhisperFullParams.ByValue params, float[] samples, int n_samples);
|
||||||
|
//int whisper_full_with_state(Pointer ctx, Pointer state, WhisperFullParams params, final float[] samples, int n_samples);
|
||||||
|
|
||||||
|
// Split the input audio in chunks and process each chunk separately using whisper_full_with_state()
|
||||||
|
// Result is stored in the default state of the context
|
||||||
|
// Not thread safe if executed in parallel on the same context.
|
||||||
|
// It seems this approach can offer some speedup in some cases.
|
||||||
|
// However, the transcription accuracy can be worse at the beginning and end of each chunk.
|
||||||
|
int whisper_full_parallel(Pointer ctx, WhisperFullParams.ByValue params, final float[] samples, int n_samples, int n_processors);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of generated text segments.
|
||||||
|
* A segment can be a few words, a sentence, or even a paragraph.
|
||||||
|
* @param ctx Pointer to WhisperContext
|
||||||
|
*/
|
||||||
|
int whisper_full_n_segments (Pointer ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state Pointer to WhisperState
|
||||||
|
*/
|
||||||
|
int whisper_full_n_segments_from_state(Pointer state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language id associated with the context's default state.
|
||||||
|
* @param ctx Pointer to WhisperContext
|
||||||
|
*/
|
||||||
|
int whisper_full_lang_id(Pointer ctx);
|
||||||
|
|
||||||
|
/** Language id associated with the provided state */
|
||||||
|
int whisper_full_lang_id_from_state(Pointer state);
|
||||||
|
|
||||||
|
|
||||||
|
/** Get the start time of the specified segment. */
|
||||||
|
long whisper_full_get_segment_t0(Pointer ctx, int i_segment);
|
||||||
|
|
||||||
|
/** Get the start time of the specified segment from the state. */
|
||||||
|
long whisper_full_get_segment_t0_from_state(Pointer state, int i_segment);
|
||||||
|
|
||||||
|
/** Get the end time of the specified segment. */
|
||||||
|
long whisper_full_get_segment_t1(Pointer ctx, int i_segment);
|
||||||
|
|
||||||
|
/** Get the end time of the specified segment from the state. */
|
||||||
|
long whisper_full_get_segment_t1_from_state(Pointer state, int i_segment);
|
||||||
|
|
||||||
|
/** Get the text of the specified segment. */
|
||||||
|
String whisper_full_get_segment_text(Pointer ctx, int i_segment);
|
||||||
|
|
||||||
|
/** Get the text of the specified segment from the state. */
|
||||||
|
String whisper_full_get_segment_text_from_state(Pointer state, int i_segment);
|
||||||
|
|
||||||
|
/** Get the number of tokens in the specified segment. */
|
||||||
|
int whisper_full_n_tokens(Pointer ctx, int i_segment);
|
||||||
|
|
||||||
|
/** Get the number of tokens in the specified segment from the state. */
|
||||||
|
int whisper_full_n_tokens_from_state(Pointer state, int i_segment);
|
||||||
|
|
||||||
|
/** Get the token text of the specified token in the specified segment. */
|
||||||
|
String whisper_full_get_token_text(Pointer ctx, int i_segment, int i_token);
|
||||||
|
|
||||||
|
|
||||||
|
/** Get the token text of the specified token in the specified segment from the state. */
|
||||||
|
String whisper_full_get_token_text_from_state(Pointer ctx, Pointer state, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get the token ID of the specified token in the specified segment. */
|
||||||
|
int whisper_full_get_token_id(Pointer ctx, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get the token ID of the specified token in the specified segment from the state. */
|
||||||
|
int whisper_full_get_token_id_from_state(Pointer state, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get token data for the specified token in the specified segment. */
|
||||||
|
WhisperTokenData whisper_full_get_token_data(Pointer ctx, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get token data for the specified token in the specified segment from the state. */
|
||||||
|
WhisperTokenData whisper_full_get_token_data_from_state(Pointer state, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get the probability of the specified token in the specified segment. */
|
||||||
|
float whisper_full_get_token_p(Pointer ctx, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/** Get the probability of the specified token in the specified segment from the state. */
|
||||||
|
float whisper_full_get_token_p_from_state(Pointer state, int i_segment, int i_token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Benchmark function for memcpy.
|
||||||
|
*
|
||||||
|
* @param nThreads Number of threads to use for the benchmark.
|
||||||
|
* @return The result of the benchmark.
|
||||||
|
*/
|
||||||
|
int whisper_bench_memcpy(int nThreads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Benchmark function for memcpy as a string.
|
||||||
|
*
|
||||||
|
* @param nThreads Number of threads to use for the benchmark.
|
||||||
|
* @return The result of the benchmark as a string.
|
||||||
|
*/
|
||||||
|
String whisper_bench_memcpy_str(int nThreads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Benchmark function for ggml_mul_mat.
|
||||||
|
*
|
||||||
|
* @param nThreads Number of threads to use for the benchmark.
|
||||||
|
* @return The result of the benchmark.
|
||||||
|
*/
|
||||||
|
int whisper_bench_ggml_mul_mat(int nThreads);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Benchmark function for ggml_mul_mat as a string.
|
||||||
|
*
|
||||||
|
* @param nThreads Number of threads to use for the benchmark.
|
||||||
|
* @return The result of the benchmark as a string.
|
||||||
|
*/
|
||||||
|
String whisper_bench_ggml_mul_mat_str(int nThreads);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.bean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by litonglinux@qq.com on 10/21/2023_7:48 AM
|
||||||
|
*/
|
||||||
|
public class WhisperSegment {
|
||||||
|
private long start, end;
|
||||||
|
private String sentence;
|
||||||
|
|
||||||
|
public WhisperSegment() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public WhisperSegment(long start, long end, String sentence) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.sentence = sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSentence() {
|
||||||
|
return sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStart(long start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnd(long end) {
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSentence(String sentence) {
|
||||||
|
this.sentence = sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "[" + start + " --> " + end + "]:" + sentence;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.callbacks;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for aborting GGML computation
|
||||||
|
* Maps to the C typedef: bool (*ggml_abort_callback)(void * data)
|
||||||
|
*/
|
||||||
|
public interface GgmlAbortCallback extends Callback {
|
||||||
|
/**
|
||||||
|
* Return true to abort the computation, false to continue
|
||||||
|
*
|
||||||
|
* @param data User data passed to the callback
|
||||||
|
* @return true to abort, false to continue
|
||||||
|
*/
|
||||||
|
boolean invoke(com.sun.jna.Pointer data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.callbacks;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.WhisperContext;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback before the encoder starts.
|
||||||
|
* If not null, called before the encoder starts.
|
||||||
|
* If it returns false, the computation is aborted.
|
||||||
|
*/
|
||||||
|
public interface WhisperEncoderBeginCallback extends Callback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method before the encoder starts.
|
||||||
|
*
|
||||||
|
* @param ctx The whisper context.
|
||||||
|
* @param state The whisper state.
|
||||||
|
* @param user_data User data.
|
||||||
|
* @return True if the computation should proceed, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean callback(Pointer ctx, Pointer state, Pointer user_data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.callbacks;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperTokenData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback to filter logits.
|
||||||
|
* Can be used to modify the logits before sampling.
|
||||||
|
* If not null, called after applying temperature to logits.
|
||||||
|
*/
|
||||||
|
public interface WhisperLogitsFilterCallback extends Callback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method to filter logits.
|
||||||
|
*
|
||||||
|
* @param ctx The whisper context.
|
||||||
|
* @param state The whisper state.
|
||||||
|
* @param tokens The array of whisper_token_data.
|
||||||
|
* @param n_tokens The number of tokens.
|
||||||
|
* @param logits The array of logits.
|
||||||
|
* @param user_data User data.
|
||||||
|
*/
|
||||||
|
void callback(Pointer ctx, Pointer state, WhisperTokenData[] tokens, int n_tokens, float[] logits, Pointer user_data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.callbacks;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.WhisperContext;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for the text segment.
|
||||||
|
* Called on every newly generated text segment.
|
||||||
|
* Use the whisper_full_...() functions to obtain the text segments.
|
||||||
|
*/
|
||||||
|
public interface WhisperNewSegmentCallback extends Callback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method for the text segment.
|
||||||
|
*
|
||||||
|
* @param ctx The whisper context.
|
||||||
|
* @param state The whisper state.
|
||||||
|
* @param n_new The number of newly generated text segments.
|
||||||
|
* @param user_data User data.
|
||||||
|
*/
|
||||||
|
void callback(Pointer ctx, Pointer state, int n_new, Pointer user_data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.callbacks;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import io.github.ggerganov.whispercpp.WhisperContext;
|
||||||
|
import io.github.ggerganov.whispercpp.model.WhisperState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for progress updates.
|
||||||
|
*/
|
||||||
|
public interface WhisperProgressCallback extends Callback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback method for progress updates.
|
||||||
|
*
|
||||||
|
* @param ctx The whisper context.
|
||||||
|
* @param state The whisper state.
|
||||||
|
* @param progress The progress value.
|
||||||
|
* @param user_data User data.
|
||||||
|
*/
|
||||||
|
void callback(Pointer ctx, Pointer state, int progress, Pointer user_data);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.ggml;
|
||||||
|
|
||||||
|
public class GgmlTensor {
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.ggml;
|
||||||
|
|
||||||
|
public enum GgmlType {
|
||||||
|
GGML_TYPE_F32,
|
||||||
|
GGML_TYPE_F16,
|
||||||
|
GGML_TYPE_Q4_0,
|
||||||
|
GGML_TYPE_Q4_1,
|
||||||
|
REMOVED_GGML_TYPE_Q4_2, // support has been removed
|
||||||
|
REMOVED_GGML_TYPE_Q4_3, // support has been removed
|
||||||
|
GGML_TYPE_Q5_0,
|
||||||
|
GGML_TYPE_Q5_1,
|
||||||
|
GGML_TYPE_Q8_0,
|
||||||
|
GGML_TYPE_Q8_1,
|
||||||
|
GGML_TYPE_I8,
|
||||||
|
GGML_TYPE_I16,
|
||||||
|
GGML_TYPE_I32,
|
||||||
|
GGML_TYPE_COUNT,
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.model;
|
||||||
|
|
||||||
|
public enum EModel {
|
||||||
|
MODEL_UNKNOWN,
|
||||||
|
MODEL_TINY,
|
||||||
|
MODEL_BASE,
|
||||||
|
MODEL_SMALL,
|
||||||
|
MODEL_MEDIUM,
|
||||||
|
MODEL_LARGE,
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package io.github.ggerganov.whispercpp;
|
||||||
|
|
||||||
|
import io.github.ggerganov.whispercpp.ggml.GgmlTensor;
|
||||||
|
import io.github.ggerganov.whispercpp.model.EModel;
|
||||||
|
|
||||||
|
public class WhisperModel {
|
||||||
|
// EModel type = EModel.MODEL_UNKNOWN;
|
||||||
|
//
|
||||||
|
// WhisperHParams hparams;
|
||||||
|
// WhisperFilters filters;
|
||||||
|
//
|
||||||
|
// // encoder.positional_embedding
|
||||||
|
// GgmlTensor e_pe;
|
||||||
|
//
|
||||||
|
// // encoder.conv1
|
||||||
|
// GgmlTensor e_conv_1_w;
|
||||||
|
// GgmlTensor e_conv_1_b;
|
||||||
|
//
|
||||||
|
// // encoder.conv2
|
||||||
|
// GgmlTensor e_conv_2_w;
|
||||||
|
// GgmlTensor e_conv_2_b;
|
||||||
|
//
|
||||||
|
// // encoder.ln_post
|
||||||
|
// GgmlTensor e_ln_w;
|
||||||
|
// GgmlTensor e_ln_b;
|
||||||
|
//
|
||||||
|
// // decoder.positional_embedding
|
||||||
|
// GgmlTensor d_pe;
|
||||||
|
//
|
||||||
|
// // decoder.token_embedding
|
||||||
|
// GgmlTensor d_te;
|
||||||
|
//
|
||||||
|
// // decoder.ln
|
||||||
|
// GgmlTensor d_ln_w;
|
||||||
|
// GgmlTensor d_ln_b;
|
||||||
|
//
|
||||||
|
// std::vector<whisper_layer_encoder> layers_encoder;
|
||||||
|
// std::vector<whisper_layer_decoder> layers_decoder;
|
||||||
|
//
|
||||||
|
// // context
|
||||||
|
// struct ggml_context * ctx;
|
||||||
|
//
|
||||||
|
// // the model memory buffer is read-only and can be shared between processors
|
||||||
|
// std::vector<uint8_t> * buf;
|
||||||
|
//
|
||||||
|
// // tensors
|
||||||
|
// int n_loaded;
|
||||||
|
// Map<String, GgmlTensor> tensors;
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.model;
|
||||||
|
|
||||||
|
import com.sun.jna.Callback;
|
||||||
|
import com.sun.jna.Pointer;
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
|
||||||
|
public class WhisperModelLoader extends Structure {
|
||||||
|
public Pointer context;
|
||||||
|
public ReadFunction read;
|
||||||
|
public EOFFunction eof;
|
||||||
|
public CloseFunction close;
|
||||||
|
|
||||||
|
public static class ReadFunction implements Callback {
|
||||||
|
public Pointer invoke(Pointer ctx, Pointer output, int readSize) {
|
||||||
|
// TODO
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EOFFunction implements Callback {
|
||||||
|
public boolean invoke(Pointer ctx) {
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CloseFunction implements Callback {
|
||||||
|
public void invoke(Pointer ctx) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public WhisperModelLoader(Pointer p) {
|
||||||
|
// super(p);
|
||||||
|
// read = new ReadFunction();
|
||||||
|
// eof = new EOFFunction();
|
||||||
|
// close = new CloseFunction();
|
||||||
|
// read.setCallback(this);
|
||||||
|
// eof.setCallback(this);
|
||||||
|
// close.setCallback(this);
|
||||||
|
// read.write();
|
||||||
|
// eof.write();
|
||||||
|
// close.write();
|
||||||
|
// }
|
||||||
|
|
||||||
|
public WhisperModelLoader() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ReadCallback extends Callback {
|
||||||
|
Pointer invoke(Pointer ctx, Pointer output, int readSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface EOFCallback extends Callback {
|
||||||
|
boolean invoke(Pointer ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface CloseCallback extends Callback {
|
||||||
|
void invoke(Pointer ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.model;
|
||||||
|
|
||||||
|
public class WhisperState {
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.model;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure representing token data.
|
||||||
|
*/
|
||||||
|
public class WhisperTokenData extends Structure {
|
||||||
|
|
||||||
|
/** Token ID. */
|
||||||
|
public int id;
|
||||||
|
|
||||||
|
/** Forced timestamp token ID. */
|
||||||
|
public int tid;
|
||||||
|
|
||||||
|
/** Probability of the token. */
|
||||||
|
public float p;
|
||||||
|
|
||||||
|
/** Log probability of the token. */
|
||||||
|
public float plog;
|
||||||
|
|
||||||
|
/** Probability of the timestamp token. */
|
||||||
|
public float pt;
|
||||||
|
|
||||||
|
/** Sum of probabilities of all timestamp tokens. */
|
||||||
|
public float ptsum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start time of the token (token-level timestamp data).
|
||||||
|
* Do not use if you haven't computed token-level timestamps.
|
||||||
|
*/
|
||||||
|
public long t0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End time of the token (token-level timestamp data).
|
||||||
|
* Do not use if you haven't computed token-level timestamps.
|
||||||
|
*/
|
||||||
|
public long t1;
|
||||||
|
|
||||||
|
/** Voice length of the token. */
|
||||||
|
public float vlen;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("id", "tid", "p", "plog", "pt", "ptsum", "t0", "t1", "vlen");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class BeamSearchParams extends Structure {
|
||||||
|
/** ref: <a href="https://github.com/openai/whisper/blob/f82bc59f5ea234d4b97fb2860842ed38519f7e65/whisper/transcribe.py#L265">...</a> */
|
||||||
|
public int beam_size;
|
||||||
|
|
||||||
|
/** ref: <a href="https://arxiv.org/pdf/2204.05424.pdf">...</a> */
|
||||||
|
public float patience;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("beam_size", "patience");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
|
||||||
|
import com.sun.jna.IntegerType;
|
||||||
|
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
public class CBool extends IntegerType implements BooleanSupplier {
|
||||||
|
public static final int SIZE = 1;
|
||||||
|
public static final CBool FALSE = new CBool(0);
|
||||||
|
public static final CBool TRUE = new CBool(1);
|
||||||
|
|
||||||
|
|
||||||
|
public CBool() {
|
||||||
|
this(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CBool(long value) {
|
||||||
|
super(SIZE, value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getAsBoolean() {
|
||||||
|
return intValue() == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return intValue() == 1 ? "true" : "false";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GreedyParams extends Structure {
|
||||||
|
/** <a href="https://github.com/openai/whisper/blob/f82bc59f5ea234d4b97fb2860842ed38519f7e65/whisper/transcribe.py#L264">...</a> */
|
||||||
|
public int best_of;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Collections.singletonList("best_of");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
import com.sun.jna.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WhisperAhead extends Structure {
|
||||||
|
|
||||||
|
public int n_text_layer;
|
||||||
|
|
||||||
|
public int n_head;
|
||||||
|
|
||||||
|
public WhisperAhead() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public WhisperAhead(int textLayer, int head) {
|
||||||
|
super();
|
||||||
|
this.n_text_layer = textLayer;
|
||||||
|
this.n_head = head;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("n_text_layer", "n_head");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends WhisperAhead implements Structure.ByReference {}
|
||||||
|
|
||||||
|
public static class ByValue extends WhisperAhead implements Structure.ByValue {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
import com.sun.jna.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WhisperAheads extends Structure {
|
||||||
|
public NativeLong n_heads;
|
||||||
|
|
||||||
|
public Pointer heads;
|
||||||
|
|
||||||
|
public WhisperAheads() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create alignment heads from an array of WhisperAhead objects
|
||||||
|
*/
|
||||||
|
public void setHeads(WhisperAhead[] aheadsArray) {
|
||||||
|
this.n_heads = new NativeLong(aheadsArray.length);
|
||||||
|
|
||||||
|
int structSize = aheadsArray[0].size();
|
||||||
|
Memory mem = new Memory(structSize * aheadsArray.length);
|
||||||
|
|
||||||
|
for (int i = 0; i < aheadsArray.length; i++) {
|
||||||
|
aheadsArray[i].write();
|
||||||
|
byte[] buffer = aheadsArray[i].getPointer().getByteArray(0, structSize);
|
||||||
|
mem.write(i * structSize, buffer, 0, buffer.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.heads = mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList("n_heads", "heads");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByReference extends WhisperAheads implements Structure.ByReference {}
|
||||||
|
|
||||||
|
public static class ByValue extends WhisperAheads implements Structure.ByValue {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
import com.sun.jna.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters for the whisper_init_from_file_with_params() function.
|
||||||
|
* If you change the order or add new parameters, make sure to update the default values in whisper.cpp:
|
||||||
|
* whisper_context_default_params()
|
||||||
|
*/
|
||||||
|
public class WhisperContextParams extends Structure {
|
||||||
|
public WhisperContextParams(Pointer p) {
|
||||||
|
super(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WhisperContextParams() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Use GPU for inference (default = true) */
|
||||||
|
public CBool use_gpu;
|
||||||
|
|
||||||
|
/** Use flash attention (default = true) */
|
||||||
|
public CBool flash_attn;
|
||||||
|
|
||||||
|
/** CUDA device to use (default = 0) */
|
||||||
|
public int gpu_device;
|
||||||
|
|
||||||
|
/** [EXPERIMENTAL] Enable token-level timestamps with DTW (default = false) */
|
||||||
|
public CBool dtw_token_timestamps;
|
||||||
|
|
||||||
|
/** [EXPERIMENTAL] Alignment heads preset for DTW */
|
||||||
|
public int dtw_aheads_preset;
|
||||||
|
|
||||||
|
/** Number of top layers to use for DTW when using WHISPER_AHEADS_N_TOP_MOST preset */
|
||||||
|
public int dtw_n_top;
|
||||||
|
|
||||||
|
public WhisperAheads.ByValue dtw_aheads;
|
||||||
|
|
||||||
|
/** DTW memory size (internal use) */
|
||||||
|
public NativeLong dtw_mem_size;
|
||||||
|
|
||||||
|
/** Use GPU for inference */
|
||||||
|
public void useGpu(boolean enable) {
|
||||||
|
use_gpu = enable ? CBool.TRUE : CBool.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Use flash attention */
|
||||||
|
public void useFlashAttn(boolean enable) {
|
||||||
|
flash_attn = enable ? CBool.TRUE : CBool.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enable DTW token-level timestamps */
|
||||||
|
public void enableDtwTokenTimestamps(boolean enable) {
|
||||||
|
dtw_token_timestamps = enable ? CBool.TRUE : CBool.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Set DTW alignment heads preset */
|
||||||
|
public void setDtwAheadsPreset(int preset) {
|
||||||
|
dtw_aheads_preset = preset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> getFieldOrder() {
|
||||||
|
return Arrays.asList(
|
||||||
|
"use_gpu",
|
||||||
|
"flash_attn",
|
||||||
|
"gpu_device",
|
||||||
|
"dtw_token_timestamps",
|
||||||
|
"dtw_aheads_preset",
|
||||||
|
"dtw_n_top",
|
||||||
|
"dtw_aheads",
|
||||||
|
"dtw_mem_size"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByValue extends WhisperContextParams implements Structure.ByValue {
|
||||||
|
public ByValue() { super(); }
|
||||||
|
public ByValue(Pointer p) { super(p); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package io.github.ggerganov.whispercpp.params;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class WhisperFilters {
|
||||||
|
int n_mel;
|
||||||
|
int n_fft;
|
||||||
|
|
||||||
|
List<Float> data;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user