Skip to content

Commit 4912c9b

Browse files
localai-botmudler
andauthored
feat(parakeet-cpp): add NVIDIA NeMo Parakeet ASR backend (parakeet.cpp) (#10084)
* feat(parakeet-cpp): L0 backend scaffold, LoadModel + AudioTranscription (text) Add a Go gRPC backend that bridges LocalAI to parakeet.cpp via the flat C-API (parakeet_capi.h), loaded with purego (cgo-less, mirrors the whisper / vibevoice-cpp backends). L0 scope: - main.go: dlopen libparakeet.so (override via PARAKEET_LIBRARY), register the C-API entry points, start the gRPC server. - goparakeetcpp.go: Load (parakeet_capi_load), AudioTranscription (parakeet_capi_transcribe_path, decoder=0 = per-arch default head), Free, serialized through base.SingleThread since the C engine is a thread-unsafe singleton. char* returns are bound as uintptr so the malloc'd buffer is freed via parakeet_capi_free_string after copy. - AudioTranscriptionStream returns a clear "not implemented in L0" error (closes the channel so the server doesn't hang), wired in L2. - Makefile: clone-at-pin + cmake (PARAKEET_VERSION for bump_deps.sh), with a local-symlink dev shortcut; run.sh / package.sh mirror whisper. - Test auto-skips without PARAKEET_BACKEND_TEST_MODEL/_WAV fixtures. Builds clean (CGO_ENABLED=0), gofmt clean, test passes. The single unsafeptr vet note in goStringFromCPtr is documented and matches the whisper backend's tolerated pattern. Word/segment timestamps (L1) and cache-aware streaming (L2) follow. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(parakeet-cpp): L1 word/segment timestamps via transcribe_path_json AudioTranscription now calls parakeet_capi_transcribe_path_json and shapes the per-word / per-token timestamps into the TranscriptResult: - Bind parakeet_capi_transcribe_path_json (purego, char* as uintptr like the other returns) and register it in main.go + the test loader. - Parse the JSON document ({"text","words":[{w,start,end,conf}], "tokens":[{id,t,conf}]}) into typed structs. - Synthesise a single whole-clip segment (parakeet emits no native segment boundaries) spanning the first word start to the last word end; token ids populate Segment.Tokens. - Attach word-level timings only when timestamp_granularities=["word"], matching the OpenAI API (segment-level default). secondsToNanos mirrors the whisper backend's nanosecond convention. Verified end-to-end against tdt_ctc-110m (f16): both the default and word-granularity specs pass; builds clean, gofmt clean, vet shows only the one documented unsafeptr note shared with the whisper backend. Cache-aware streaming (L2) follows. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(parakeet-cpp): L2 cache-aware streaming with EOU segmentation Wire AudioTranscriptionStream to the streaming RNN-T C-API: - Bind parakeet_capi_stream_{begin,feed,finalize,free}; feed takes 16 kHz mono float PCM ([]float32 via purego) and writes *eou_out on <EOU>/<EOB>. - Decode opts.Dst to 16 kHz mono PCM (utils.AudioToWav + go-audio, same as the whisper backend), feed it in 1 s chunks, and emit each newly-finalized text run as a TranscriptStreamResponse delta. - <EOU>/<EOB> events close the current segment; a closing FinalResult carries the full transcript plus the per-utterance segments (with a whole-clip fallback segment when no EOU fired). - stream_begin returns 0 for non-streaming models, surfaced as a clear error instead of an empty stream. Honours context cancellation between chunks. Frees every malloc'd delta and the session. Verified end-to-end against realtime_eou_120m-v1 (f16): the streamed transcript matches the offline 110m reference word-for-word, deltas reconstruct the final text, and the spec passes alongside the offline specs. Builds clean, gofmt clean, vet shows only the shared documented unsafeptr note. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(parakeet-cpp): L3 register backend in build/CI/gallery (whisper parity) Wire the new Go gRPC parakeet-cpp backend (parakeet.cpp ggml port of NVIDIA NeMo Parakeet ASR) into LocalAI's build/CI/gallery surfaces, matching the existing ggml whisper Go backend 1:1. - .github/backend-matrix.yml: add 11 linux entries + 1 darwin entry mirroring every whisper build (cpu amd64/arm64, intel sycl f32/f16, vulkan amd64/arm64, nvidia cuda-12, nvidia cuda-13, nvidia-l4t-arm64, nvidia-l4t-cuda-13-arm64, rocm hipblas, metal-darwin-arm64), all on ./backend/Dockerfile.golang with backend: "parakeet-cpp" and -*-parakeet-cpp tag-suffixes. - scripts/changed-backends.js: explicit inferBackendPath branch resolving parakeet-cpp to backend/go/parakeet-cpp/ before the generic golang branch. - .github/workflows/bump_deps.yaml: track the PARAKEET_VERSION pin in backend/go/parakeet-cpp/Makefile (repo mudler/parakeet.cpp, branch master). - backend/index.yaml: add &parakeetcpp meta + latest/development image entries for every matrix tag-suffix. - Makefile: add backends/parakeet-cpp to .NOTPARALLEL, BACKEND_PARAKEET_CPP definition, docker-build target eval, and test-extra-backend-parakeet-cpp- transcription target (mirrors test-extra-backend-whisper-transcription). Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(parakeet-cpp): L4 gallery importer for parakeet GGUFs Add ParakeetCppImporter so parakeet.cpp GGUFs auto-detect on /import-model and route to the parakeet-cpp backend (it also surfaces in /backends/known, which drives the import dropdown). - Match is narrow: a .gguf whose name carries a parakeet architecture token (<arch>-<size>-<quant>.gguf, e.g. tdt_ctc-110m-f16.gguf, rnnt-0.6b-q4_k.gguf, realtime_eou_120m-v1-q8_0.gguf), a direct URL to one, or preferences.backend="parakeet-cpp". It deliberately does NOT claim arbitrary llama-style GGUFs, nor the upstream nvidia/parakeet-* NeMo repos (.nemo, not runnable here). - Registered in the ASR batch BEFORE LlamaCPPImporter so its GGUFs aren't swallowed by the generic .gguf importer. - Import nests files under parakeet-cpp/models/<name>/, defaults to the smallest quant (q4_k, near-lossless on parakeet) with a size-ladder fallback, and honours preferences.quantizations / name / description. Tested with synthetic HF details (no network): metadata, positive matches (HF repo, direct URL, preference), narrowness negatives (llama GGUF, NeMo repo), and import (default quant, override, direct URL), 9 specs pass, build/vet/gofmt clean. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * docs(parakeet-cpp): document the parakeet-cpp transcription backend Add parakeet-cpp to the audio-to-text backend list and a dedicated usage section: direct GGUF import (auto-detects to the backend), model YAML, word-level timestamps via timestamp_granularities[]=word, and cache-aware streaming with the realtime_eou model. Points at the mudler/parakeet-cpp-gguf collection repo. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * ci(parakeet-cpp): wire transcription gRPC e2e test into test-extra The L3 commit added the test-extra-backend-parakeet-cpp-transcription Makefile target but never invoked it in CI. Mirror the whisper job: - Add a parakeet-cpp output to detect-changes (emitted by changed-backends.js from the matrix entry). - Add tests-parakeet-cpp-grpc-transcription, gated on the parakeet-cpp path filter / run-all, building the backend image and running the transcription e2e against tdt_ctc-110m + the JFK clip. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * style(parakeet-cpp): drop em dashes from comments and docs Replace em dashes with plain punctuation in the backend comments, the importer, package.sh, and the audio-to-text docs section (and use "and" instead of the multiplication sign). No behaviour change. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(gallery): add parakeet-cpp f16 models to the model gallery Add the 10 NVIDIA Parakeet models (f16, the recommended quality/speed default) as gallery entries that install on the parakeet-cpp backend from mudler/parakeet-cpp-gguf: tdt_ctc-110m/1.1b, tdt-0.6b-v2/v3, tdt-1.1b, ctc-0.6b/1.1b, rnnt-0.6b/1.1b, and the cache-aware streaming realtime_eou_120m-v1. Each pins the file sha256 and routes transcript usecases to the backend. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(parakeet-cpp): satisfy govet lint + bump PARAKEET_VERSION - goparakeetcpp.go: //nolint:govet on the C-owned-pointer unsafe.Pointer conversion (golangci-lint reports new-only issues, so unlike the whisper backend's identical line this one is flagged). - Makefile: bump PARAKEET_VERSION to the current parakeet.cpp master commit (the previous pin's commit no longer exists after upstream history was squashed), so the backend image clone/build resolves again. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(parakeet-cpp): pin PARAKEET_VERSION to a tag-stable commit The previous SHA pin was orphaned when parakeet.cpp's single-commit master was amended/force-pushed, so the backend image clone (git fetch <sha>) failed across every build variant. Repoint to 845c29e, which upstream now keeps permanently fetchable via the `localai-backend-pin` tag, so future upstream amends no longer break the backend build. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(parakeet-cpp): init the ggml submodule in the backend image clone The backend Dockerfile clones parakeet.cpp at PARAKEET_VERSION with a shallow fetch + checkout but never initialised submodules, so third_party/ggml was empty and the parakeet.cpp cmake build failed at `add_subdirectory(third_party/ggml)` (CMakeLists.txt:53) on every build variant. Add `git submodule update --init --recursive --depth 1 --single-branch` after checkout, mirroring the whisper backend. Verified locally: clone + submodule + cmake configure now succeeds. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(parakeet-cpp): statically link ggml into libparakeet.so The shared libparakeet.so linked ggml's shared libs (libggml*.so), but the package only ships libparakeet.so, so at runtime dlopen failed with "libggml.so.0: cannot open shared object file" (the e2e transcription test panicked on load). Build ggml static + PIC (BUILD_SHARED_LIBS=OFF, CMAKE_POSITION_INDEPENDENT_CODE=ON) so libparakeet.so embeds ggml and depends only on system libs already present in the runtime image. Verified locally: ldd shows no libggml dependency. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(parakeet-cpp): non-streaming fallback in AudioTranscriptionStream The e2e streaming test ran AudioTranscriptionStream against tdt_ctc-110m (not a cache-aware streaming model), so stream_begin returned 0 and the call errored. Per LocalAI's streaming contract (and the whisper backend), a non-streaming model should fall back to a single offline transcription emitted as one delta plus a closing FinalResult. Do that instead of erroring, so the streaming endpoint works for every parakeet model. Verified locally: the streaming spec passes against the non-streaming 110m model via fallback. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
1 parent 12d1f3a commit 4912c9b

18 files changed

Lines changed: 1706 additions & 1 deletion

File tree

.github/backend-matrix.yml

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,19 @@ include:
716716
dockerfile: "./backend/Dockerfile.golang"
717717
context: "./"
718718
ubuntu-version: '2404'
719+
- build-type: 'cublas'
720+
cuda-major-version: "12"
721+
cuda-minor-version: "8"
722+
platforms: 'linux/amd64'
723+
tag-latest: 'auto'
724+
tag-suffix: '-gpu-nvidia-cuda-12-parakeet-cpp'
725+
runs-on: 'ubuntu-latest'
726+
base-image: "ubuntu:24.04"
727+
skip-drivers: 'false'
728+
backend: "parakeet-cpp"
729+
dockerfile: "./backend/Dockerfile.golang"
730+
context: "./"
731+
ubuntu-version: '2404'
719732
- build-type: 'cublas'
720733
cuda-major-version: "12"
721734
cuda-minor-version: "8"
@@ -1556,6 +1569,19 @@ include:
15561569
dockerfile: "./backend/Dockerfile.golang"
15571570
context: "./"
15581571
ubuntu-version: '2404'
1572+
- build-type: 'cublas'
1573+
cuda-major-version: "13"
1574+
cuda-minor-version: "0"
1575+
platforms: 'linux/amd64'
1576+
tag-latest: 'auto'
1577+
tag-suffix: '-gpu-nvidia-cuda-13-parakeet-cpp'
1578+
runs-on: 'ubuntu-latest'
1579+
base-image: "ubuntu:24.04"
1580+
skip-drivers: 'false'
1581+
backend: "parakeet-cpp"
1582+
dockerfile: "./backend/Dockerfile.golang"
1583+
context: "./"
1584+
ubuntu-version: '2404'
15591585
- build-type: 'cublas'
15601586
cuda-major-version: "13"
15611587
cuda-minor-version: "0"
@@ -1569,6 +1595,19 @@ include:
15691595
backend: "whisper"
15701596
dockerfile: "./backend/Dockerfile.golang"
15711597
context: "./"
1598+
- build-type: 'cublas'
1599+
cuda-major-version: "13"
1600+
cuda-minor-version: "0"
1601+
platforms: 'linux/arm64'
1602+
skip-drivers: 'false'
1603+
tag-latest: 'auto'
1604+
tag-suffix: '-nvidia-l4t-cuda-13-arm64-parakeet-cpp'
1605+
base-image: "ubuntu:24.04"
1606+
ubuntu-version: '2404'
1607+
runs-on: 'ubuntu-24.04-arm'
1608+
backend: "parakeet-cpp"
1609+
dockerfile: "./backend/Dockerfile.golang"
1610+
context: "./"
15721611
- build-type: 'cublas'
15731612
cuda-major-version: "13"
15741613
cuda-minor-version: "0"
@@ -2944,6 +2983,115 @@ include:
29442983
dockerfile: "./backend/Dockerfile.golang"
29452984
context: "./"
29462985
ubuntu-version: '2404'
2986+
# parakeet-cpp
2987+
- build-type: ''
2988+
cuda-major-version: ""
2989+
cuda-minor-version: ""
2990+
platforms: 'linux/amd64'
2991+
platform-tag: 'amd64'
2992+
tag-latest: 'auto'
2993+
tag-suffix: '-cpu-parakeet-cpp'
2994+
runs-on: 'ubuntu-latest'
2995+
base-image: "ubuntu:24.04"
2996+
skip-drivers: 'false'
2997+
backend: "parakeet-cpp"
2998+
dockerfile: "./backend/Dockerfile.golang"
2999+
context: "./"
3000+
ubuntu-version: '2404'
3001+
- build-type: ''
3002+
cuda-major-version: ""
3003+
cuda-minor-version: ""
3004+
platforms: 'linux/arm64'
3005+
platform-tag: 'arm64'
3006+
tag-latest: 'auto'
3007+
tag-suffix: '-cpu-parakeet-cpp'
3008+
runs-on: 'ubuntu-24.04-arm'
3009+
base-image: "ubuntu:24.04"
3010+
skip-drivers: 'false'
3011+
backend: "parakeet-cpp"
3012+
dockerfile: "./backend/Dockerfile.golang"
3013+
context: "./"
3014+
ubuntu-version: '2404'
3015+
- build-type: 'sycl_f32'
3016+
cuda-major-version: ""
3017+
cuda-minor-version: ""
3018+
platforms: 'linux/amd64'
3019+
tag-latest: 'auto'
3020+
tag-suffix: '-gpu-intel-sycl-f32-parakeet-cpp'
3021+
runs-on: 'ubuntu-latest'
3022+
base-image: "intel/oneapi-basekit:2025.3.0-0-devel-ubuntu24.04"
3023+
skip-drivers: 'false'
3024+
backend: "parakeet-cpp"
3025+
dockerfile: "./backend/Dockerfile.golang"
3026+
context: "./"
3027+
ubuntu-version: '2404'
3028+
- build-type: 'sycl_f16'
3029+
cuda-major-version: ""
3030+
cuda-minor-version: ""
3031+
platforms: 'linux/amd64'
3032+
tag-latest: 'auto'
3033+
tag-suffix: '-gpu-intel-sycl-f16-parakeet-cpp'
3034+
runs-on: 'ubuntu-latest'
3035+
base-image: "intel/oneapi-basekit:2025.3.0-0-devel-ubuntu24.04"
3036+
skip-drivers: 'false'
3037+
backend: "parakeet-cpp"
3038+
dockerfile: "./backend/Dockerfile.golang"
3039+
context: "./"
3040+
ubuntu-version: '2404'
3041+
- build-type: 'vulkan'
3042+
cuda-major-version: ""
3043+
cuda-minor-version: ""
3044+
platforms: 'linux/amd64'
3045+
platform-tag: 'amd64'
3046+
tag-latest: 'auto'
3047+
tag-suffix: '-gpu-vulkan-parakeet-cpp'
3048+
runs-on: 'ubuntu-latest'
3049+
base-image: "ubuntu:24.04"
3050+
skip-drivers: 'false'
3051+
backend: "parakeet-cpp"
3052+
dockerfile: "./backend/Dockerfile.golang"
3053+
context: "./"
3054+
ubuntu-version: '2404'
3055+
- build-type: 'vulkan'
3056+
cuda-major-version: ""
3057+
cuda-minor-version: ""
3058+
platforms: 'linux/arm64'
3059+
platform-tag: 'arm64'
3060+
tag-latest: 'auto'
3061+
tag-suffix: '-gpu-vulkan-parakeet-cpp'
3062+
runs-on: 'ubuntu-24.04-arm'
3063+
base-image: "ubuntu:24.04"
3064+
skip-drivers: 'false'
3065+
backend: "parakeet-cpp"
3066+
dockerfile: "./backend/Dockerfile.golang"
3067+
context: "./"
3068+
ubuntu-version: '2404'
3069+
- build-type: 'cublas'
3070+
cuda-major-version: "12"
3071+
cuda-minor-version: "0"
3072+
platforms: 'linux/arm64'
3073+
skip-drivers: 'false'
3074+
tag-latest: 'auto'
3075+
tag-suffix: '-nvidia-l4t-arm64-parakeet-cpp'
3076+
base-image: "nvcr.io/nvidia/l4t-jetpack:r36.4.0"
3077+
runs-on: 'ubuntu-24.04-arm'
3078+
backend: "parakeet-cpp"
3079+
dockerfile: "./backend/Dockerfile.golang"
3080+
context: "./"
3081+
ubuntu-version: '2204'
3082+
- build-type: 'hipblas'
3083+
cuda-major-version: ""
3084+
cuda-minor-version: ""
3085+
platforms: 'linux/amd64'
3086+
tag-latest: 'auto'
3087+
tag-suffix: '-gpu-rocm-hipblas-parakeet-cpp'
3088+
base-image: "rocm/dev-ubuntu-24.04:7.2.1"
3089+
runs-on: 'ubuntu-latest'
3090+
skip-drivers: 'false'
3091+
backend: "parakeet-cpp"
3092+
dockerfile: "./backend/Dockerfile.golang"
3093+
context: "./"
3094+
ubuntu-version: '2404'
29473095
# acestep-cpp
29483096
- build-type: ''
29493097
cuda-major-version: ""
@@ -3976,6 +4124,10 @@ includeDarwin:
39764124
tag-suffix: "-metal-darwin-arm64-whisper"
39774125
build-type: "metal"
39784126
lang: "go"
4127+
- backend: "parakeet-cpp"
4128+
tag-suffix: "-metal-darwin-arm64-parakeet-cpp"
4129+
build-type: "metal"
4130+
lang: "go"
39794131
- backend: "acestep-cpp"
39804132
tag-suffix: "-metal-darwin-arm64-acestep-cpp"
39814133
build-type: "metal"

.github/workflows/bump_deps.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ jobs:
3030
variable: "WHISPER_CPP_VERSION"
3131
branch: "master"
3232
file: "backend/go/whisper/Makefile"
33+
- repository: "mudler/parakeet.cpp"
34+
variable: "PARAKEET_VERSION"
35+
branch: "master"
36+
file: "backend/go/parakeet-cpp/Makefile"
3337
- repository: "leejet/stable-diffusion.cpp"
3438
variable: "STABLEDIFFUSION_GGML_VERSION"
3539
branch: "master"

.github/workflows/test-extra.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ jobs:
4646
speaker-recognition: ${{ steps.detect.outputs.speaker-recognition }}
4747
sherpa-onnx: ${{ steps.detect.outputs.sherpa-onnx }}
4848
whisper: ${{ steps.detect.outputs.whisper }}
49+
parakeet-cpp: ${{ steps.detect.outputs.parakeet-cpp }}
4950
steps:
5051
- name: Checkout repository
5152
uses: actions/checkout@v6
@@ -633,6 +634,26 @@ jobs:
633634
- name: Build whisper backend image and run transcription gRPC e2e tests
634635
run: |
635636
make test-extra-backend-whisper-transcription
637+
# Parakeet ASR via the parakeet-cpp backend (C++/ggml port of NeMo
638+
# Parakeet). Drives AudioTranscription (offline, with word timestamps) on
639+
# tdt_ctc-110m + the JFK 11s clip.
640+
tests-parakeet-cpp-grpc-transcription:
641+
needs: detect-changes
642+
if: needs.detect-changes.outputs.parakeet-cpp == 'true' || needs.detect-changes.outputs.run-all == 'true'
643+
runs-on: ubuntu-latest
644+
timeout-minutes: 90
645+
steps:
646+
- name: Clone
647+
uses: actions/checkout@v6
648+
with:
649+
submodules: true
650+
- name: Setup Go
651+
uses: actions/setup-go@v5
652+
with:
653+
go-version: '1.25.4'
654+
- name: Build parakeet-cpp backend image and run transcription gRPC e2e tests
655+
run: |
656+
make test-extra-backend-parakeet-cpp-transcription
636657
# VITS TTS via the sherpa-onnx backend. Drives both TTS (file write) and
637658
# TTSStream (PCM chunks) on the e2e-backends harness.
638659
tests-sherpa-onnx-grpc-tts:

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Disable parallel execution for backend builds
2-
.NOTPARALLEL: backends/diffusers backends/llama-cpp backends/turboquant backends/outetts backends/piper backends/stablediffusion-ggml backends/whisper backends/faster-whisper backends/silero-vad backends/local-store backends/huggingface backends/rfdetr backends/rfdetr-cpp backends/insightface backends/speaker-recognition backends/kitten-tts backends/kokoro backends/chatterbox backends/llama-cpp-darwin backends/neutts build-darwin-python-backend build-darwin-go-backend backends/mlx backends/diffuser-darwin backends/mlx-vlm backends/mlx-audio backends/mlx-distributed backends/stablediffusion-ggml-darwin backends/vllm backends/vllm-omni backends/sglang backends/moonshine backends/pocket-tts backends/qwen-tts backends/faster-qwen3-tts backends/qwen-asr backends/nemo backends/voxcpm backends/whisperx backends/ace-step backends/acestep-cpp backends/fish-speech backends/voxtral backends/opus backends/trl backends/llama-cpp-quantization backends/kokoros backends/sam3-cpp backends/qwen3-tts-cpp backends/vibevoice-cpp backends/localvqe backends/tinygrad backends/sherpa-onnx backends/ds4 backends/ds4-darwin backends/liquid-audio
2+
.NOTPARALLEL: backends/diffusers backends/llama-cpp backends/turboquant backends/outetts backends/piper backends/stablediffusion-ggml backends/whisper backends/parakeet-cpp backends/faster-whisper backends/silero-vad backends/local-store backends/huggingface backends/rfdetr backends/rfdetr-cpp backends/insightface backends/speaker-recognition backends/kitten-tts backends/kokoro backends/chatterbox backends/llama-cpp-darwin backends/neutts build-darwin-python-backend build-darwin-go-backend backends/mlx backends/diffuser-darwin backends/mlx-vlm backends/mlx-audio backends/mlx-distributed backends/stablediffusion-ggml-darwin backends/vllm backends/vllm-omni backends/sglang backends/moonshine backends/pocket-tts backends/qwen-tts backends/faster-qwen3-tts backends/qwen-asr backends/nemo backends/voxcpm backends/whisperx backends/ace-step backends/acestep-cpp backends/fish-speech backends/voxtral backends/opus backends/trl backends/llama-cpp-quantization backends/kokoros backends/sam3-cpp backends/qwen3-tts-cpp backends/vibevoice-cpp backends/localvqe backends/tinygrad backends/sherpa-onnx backends/ds4 backends/ds4-darwin backends/liquid-audio
33

44
GOCMD=go
55
GOTEST=$(GOCMD) test
@@ -991,6 +991,19 @@ test-extra-backend-whisper-transcription: docker-build-whisper
991991
BACKEND_TEST_CAPS=health,load,transcription \
992992
$(MAKE) test-extra-backend
993993

994+
## Audio transcription wrapper for the parakeet-cpp (parakeet.cpp ggml port)
995+
## backend. Mirrors test-extra-backend-whisper-transcription: drives the
996+
## AudioTranscription / AudioTranscriptionStream RPCs against a published
997+
## Parakeet GGUF using the JFK 11s clip from whisper.cpp's CI samples. Not
998+
## part of the default test suite - run explicitly once the pinned model URL
999+
## is reachable.
1000+
test-extra-backend-parakeet-cpp-transcription: docker-build-parakeet-cpp
1001+
BACKEND_IMAGE=local-ai-backend:parakeet-cpp \
1002+
BACKEND_TEST_MODEL_URL=https://huggingface.co/mudler/parakeet-cpp-gguf/resolve/main/tdt_ctc-110m-f16.gguf \
1003+
BACKEND_TEST_AUDIO_URL=https://github.com/ggml-org/whisper.cpp/raw/master/samples/jfk.wav \
1004+
BACKEND_TEST_CAPS=health,load,transcription \
1005+
$(MAKE) test-extra-backend
1006+
9941007
## LocalVQE audio transform (joint AEC + noise suppression + dereverb).
9951008
## Exercises the audio_transform capability end-to-end: batch transform
9961009
## of a real WAV fixture and bidi streaming of synthetic silent frames.
@@ -1149,6 +1162,7 @@ BACKEND_HUGGINGFACE = huggingface|golang|.|false|true
11491162
BACKEND_SILERO_VAD = silero-vad|golang|.|false|true
11501163
BACKEND_STABLEDIFFUSION_GGML = stablediffusion-ggml|golang|.|--progress=plain|true
11511164
BACKEND_WHISPER = whisper|golang|.|false|true
1165+
BACKEND_PARAKEET_CPP = parakeet-cpp|golang|.|false|true
11521166
BACKEND_VOXTRAL = voxtral|golang|.|false|true
11531167
BACKEND_ACESTEP_CPP = acestep-cpp|golang|.|false|true
11541168
BACKEND_QWEN3_TTS_CPP = qwen3-tts-cpp|golang|.|false|true
@@ -1236,6 +1250,7 @@ $(eval $(call generate-docker-build-target,$(BACKEND_HUGGINGFACE)))
12361250
$(eval $(call generate-docker-build-target,$(BACKEND_SILERO_VAD)))
12371251
$(eval $(call generate-docker-build-target,$(BACKEND_STABLEDIFFUSION_GGML)))
12381252
$(eval $(call generate-docker-build-target,$(BACKEND_WHISPER)))
1253+
$(eval $(call generate-docker-build-target,$(BACKEND_PARAKEET_CPP)))
12391254
$(eval $(call generate-docker-build-target,$(BACKEND_VOXTRAL)))
12401255
$(eval $(call generate-docker-build-target,$(BACKEND_OPUS)))
12411256
$(eval $(call generate-docker-build-target,$(BACKEND_RERANKERS)))

backend/go/parakeet-cpp/.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.cache/
2+
sources/
3+
build/
4+
package/
5+
parakeet-cpp-grpc
6+
# build artifacts staged in-tree by the Makefile (cp from sources/) or
7+
# symlinked for local dev; the real sources live in parakeet.cpp upstream.
8+
*.so
9+
*.so.*
10+
parakeet_capi.h
11+
compile_commands.json

backend/go/parakeet-cpp/Makefile

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# parakeet-cpp backend Makefile.
2+
#
3+
# Upstream pin lives below as PARAKEET_VERSION?=845c29ec3f0aeb70876c5ac1e09db116325e7181
4+
# (.github/bump_deps.sh) can find and update it - matches the
5+
# whisper.cpp / ds4 / vibevoice-cpp convention.
6+
#
7+
# Local dev shortcut: if you already have an out-of-tree parakeet.cpp
8+
# build, you can symlink the .so + header into this directory and skip
9+
# the clone/cmake steps entirely, e.g.:
10+
#
11+
# ln -sf /path/to/parakeet.cpp/build-shared/libparakeet.so .
12+
# ln -sf /path/to/parakeet.cpp/include/parakeet_capi.h .
13+
# go build -o parakeet-cpp-grpc .
14+
#
15+
# That's what the L0 smoke test uses. The default target below does the
16+
# proper clone-at-pin + cmake build so CI doesn't need a side-checkout.
17+
18+
PARAKEET_VERSION?=845c29ec3f0aeb70876c5ac1e09db116325e7181
19+
PARAKEET_REPO?=https://github.com/mudler/parakeet.cpp
20+
21+
GOCMD?=go
22+
GO_TAGS?=
23+
JOBS?=$(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
24+
25+
BUILD_TYPE?=
26+
NATIVE?=false
27+
28+
# Build ggml statically into libparakeet.so (PIC) so the shared lib is
29+
# self-contained: dlopen needs no libggml*.so alongside it, only system libs
30+
# (libstdc++/libgomp/libc) that the runtime image already provides.
31+
CMAKE_ARGS?=-DCMAKE_BUILD_TYPE=Release -DPARAKEET_SHARED=ON -DPARAKEET_BUILD_CLI=OFF -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON
32+
33+
ifeq ($(NATIVE),false)
34+
CMAKE_ARGS+=-DGGML_NATIVE=OFF
35+
endif
36+
37+
ifeq ($(BUILD_TYPE),cublas)
38+
CMAKE_ARGS+=-DGGML_CUDA=ON
39+
else ifeq ($(BUILD_TYPE),openblas)
40+
CMAKE_ARGS+=-DGGML_BLAS=ON -DGGML_BLAS_VENDOR=OpenBLAS
41+
else ifeq ($(BUILD_TYPE),hipblas)
42+
CMAKE_ARGS+=-DGGML_HIP=ON
43+
else ifeq ($(BUILD_TYPE),vulkan)
44+
CMAKE_ARGS+=-DGGML_VULKAN=ON
45+
endif
46+
47+
.PHONY: parakeet-cpp-grpc package build clean purge test all
48+
49+
all: parakeet-cpp-grpc
50+
51+
# Clone the upstream parakeet.cpp source at the pinned commit. Directory
52+
# acts as the target so make only re-clones when missing. After a
53+
# PARAKEET_VERSION bump, run 'make purge && make' to refetch.
54+
sources/parakeet.cpp:
55+
mkdir -p sources/parakeet.cpp
56+
cd sources/parakeet.cpp && \
57+
git init -q && \
58+
git remote add origin $(PARAKEET_REPO) && \
59+
git fetch --depth 1 origin $(PARAKEET_VERSION) && \
60+
git checkout FETCH_HEAD && \
61+
git submodule update --init --recursive --depth 1 --single-branch
62+
63+
# Build the shared lib + header out-of-tree, then stage them next to the
64+
# Go sources so purego.Dlopen("libparakeet.so") and the cgo-less build
65+
# both pick them up.
66+
libparakeet.so: sources/parakeet.cpp
67+
cmake -B sources/parakeet.cpp/build-shared -S sources/parakeet.cpp $(CMAKE_ARGS)
68+
cmake --build sources/parakeet.cpp/build-shared --config Release -j$(JOBS)
69+
cp -fv sources/parakeet.cpp/build-shared/libparakeet.so* ./ 2>/dev/null || true
70+
cp -fv sources/parakeet.cpp/include/parakeet_capi.h ./
71+
72+
parakeet-cpp-grpc: libparakeet.so main.go goparakeetcpp.go
73+
CGO_ENABLED=0 $(GOCMD) build -tags "$(GO_TAGS)" -o parakeet-cpp-grpc .
74+
75+
package: parakeet-cpp-grpc
76+
bash package.sh
77+
78+
build: package
79+
80+
# Test target. Smoke test is gated on PARAKEET_BACKEND_TEST_MODEL +
81+
# PARAKEET_BACKEND_TEST_WAV; without them the spec auto-skips.
82+
test:
83+
LD_LIBRARY_PATH=$(CURDIR):$$LD_LIBRARY_PATH $(GOCMD) test ./... -count=1
84+
85+
clean: purge
86+
rm -rf libparakeet.so* parakeet_capi.h package parakeet-cpp-grpc
87+
88+
purge:
89+
rm -rf sources/parakeet.cpp

0 commit comments

Comments
 (0)