Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/transcription-parakeet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- `rnnt` model type: plain RNN-T (Transducer) checkpoints — e.g. the Transducer
branch of NeMo hybrid `EncDecHybridRNNTCTCBPEModel` models such as the Georgian
`stt_ka_fastconformer_hybrid_large_pc` — auto-detected from GGUF metadata and
exposed in the public `ModelType` union. The vendored converter gains rnnt
export (`parakeet.rnnt.*` metadata + `rnnt.predict/joint` tensors, `--type
rnnt` in `convert-nemo.sh`). Requires a `parakeet-cpp` engine that ships the
rnnt head; the registry port pin must be bumped past the engine-side merge
before this is functional.

## [0.9.1] - 2026-07-08

### Fixed
Expand Down
10 changes: 6 additions & 4 deletions packages/transcription-parakeet/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# transcription-parakeet

This library simplifies running NVIDIA Parakeet speech-to-text and Sortformer speaker-diarization inference within QVAC runtime applications. It provides an easy interface to load, execute, and manage Parakeet inference instances, supporting CTC, TDT, EOU, and Sortformer checkpoints from a single binding.
This library simplifies running NVIDIA Parakeet speech-to-text and Sortformer speaker-diarization inference within QVAC runtime applications. It provides an easy interface to load, execute, and manage Parakeet inference instances, supporting CTC, TDT, RNNT, EOU, and Sortformer checkpoints from a single binding.

## Table of Contents

Expand Down Expand Up @@ -179,7 +179,7 @@ The three underlying scripts are also flag-driven if you want to run them separa
setup-venv.sh [--python <bin>] [--venv <path>] [--force] [--help]
download-models.sh [--type ctc|tdt|eou|sortformer|sortformer-streaming-v2.1|all]
[--output <dir>] [--force] [--help]
convert-nemo.sh [--type ctc|tdt|eou|sortformer|sortformer-streaming-v2.1|all]
convert-nemo.sh [--type ctc|tdt|rnnt|eou|sortformer|sortformer-streaming-v2.1|all]
[--quant f16|q8_0|q5_0|q4_0|f32]
[--python <bin>]
[--nemo-dir <dir>] [--output <dir>] [--force] [--help]
Expand All @@ -194,6 +194,7 @@ convert-nemo.sh [--type ctc|tdt|eou|sortformer|sortformer-streaming-v2.1|all]
| `eou` | [`nvidia/parakeet_realtime_eou_120m-v1`](https://huggingface.co/nvidia/parakeet_realtime_eou_120m-v1) |
| `sortformer` | [`nvidia/diar_sortformer_4spk-v1`](https://huggingface.co/nvidia/diar_sortformer_4spk-v1) |
| `sortformer-streaming-v2.1` | [`nvidia/diar_streaming_sortformer_4spk-v2.1`](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2.1) |
| `rnnt` | [`nvidia/stt_ka_fastconformer_hybrid_large_pc`](https://huggingface.co/nvidia/stt_ka_fastconformer_hybrid_large_pc) — convert-only; `download-models.sh` has no `rnnt` entry yet, place the `.nemo` manually |

NVIDIA Open Model License -- see each repo's model card for terms.

Expand Down Expand Up @@ -224,7 +225,7 @@ Most users interact with the package through `index.js`. From that entrypoint we
| | `backendsDir` | Root directory for dynamically-loaded ggml backend `.so` files (Vulkan, OpenCL, per-arch CPU variants on Android). Defaults to the package's `prebuilds/` folder; the native addon appends `<bare-target>/<module-name>` before scanning. Pass an explicit path when prebuilds live elsewhere — e.g. Android `ApplicationInfo.nativeLibraryDir` when backend libs ship inside the APK. No-op on Apple (statically linked). |
| | `openclCacheDir` | Persistent directory for ggml-opencl's compiled program-binary cache (`$GGML_OPENCL_CACHE_DIR`). Android-only; pass the host app's cache directory (e.g. `Context.getCacheDir()`) to skip cold `clBuildProgram` on every process start. Ignored on other platforms. |

The model type (CTC / TDT / EOU / Sortformer) is **auto-detected from the GGUF metadata**, so callers don't need to pass `modelType`. Other knobs (`captionEnabled`, `timestampsEnabled`, `seed`, `sampleRate`, `channels`) keep sensible defaults.
The model type (CTC / TDT / RNNT / EOU / Sortformer) is **auto-detected from the GGUF metadata**, so callers don't need to pass `modelType`. Other knobs (`captionEnabled`, `timestampsEnabled`, `seed`, `sampleRate`, `channels`) keep sensible defaults.

**Sortformer Streaming Diarization (v2.1 + AOSC).** parakeet-cpp ships
two streaming-diarization paths picked automatically by the GGUF:
Expand Down Expand Up @@ -462,7 +463,7 @@ npm run setup-models -- -t tdt -q q8_0
### 3. Run the bundled examples

```bash
# Single-file transcription (any model type -- CTC / TDT / EOU / Sortformer)
# Single-file transcription (any model type -- CTC / TDT / RNNT / EOU / Sortformer)
bare examples/transcribe.js \
--model models/parakeet-tdt-0.6b-v3.q8_0.gguf \
--audio examples/samples/sample-16k.wav
Expand Down Expand Up @@ -499,6 +500,7 @@ The live-mic examples capture the default input device via `sox -d` (install: `b
| **CTC** | English | argmax CTC | ~ 700 MiB | Fast, no PnC. |
| **TDT** | ~25 | RNN-T greedy + duration | ~ 715 MiB | Recommended default; PnC + auto-detect. |
| **EOU** | English | RNN-T greedy + `<EOU>` | ~ 132 MiB | Streaming-trained; native end-of-turn token. |
| **RNNT** | checkpoint-dependent (e.g. Georgian for `stt_ka_fastconformer_hybrid_large_pc`) | plain RNN-T greedy | checkpoint-dependent | Duration-less Transducer heads, incl. the RNN-T branch of hybrid transducer+CTC checkpoints. Requires a parakeet-cpp engine with the `rnnt` head. |
| **Sortformer v1** | n/a | Diarization head (sliding history) | ~ 141 MiB | 4-speaker. **Default for offline diarization.** |
| **Sortformer v2.1 + AOSC** | n/a | Diarization head + speaker cache | ~ 141 MiB | 4-speaker. **Default for streaming diarization.** AOSC anchors speaker slots across silence/re-entry; auto-detected via GGUF metadata tag `parakeet.model_variant`. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct Transcript {
float end;
size_t id;
// True when this segment ends on a recognised end-of-utterance boundary
// (EOU streaming: `<EOU>` token; CTC/TDT/Sortformer always leave this
// (EOU streaming: `<EOU>` token; CTC/TDT/RNNT/Sortformer always leave this
// false). The text field still carries any speech tokens decoded in the
// same chunk; consumers that want a turn-end signal independent of the
// transcript should test this flag.
Expand Down Expand Up @@ -60,6 +60,7 @@ struct Transcript {
enum class ModelType : std::uint8_t {
CTC, // English-only, fast transcription with punctuation/capitalization
TDT, // Multilingual (~25 languages) with auto-detection
RNNT, // Plain RNN-T (Transducer); e.g. the Georgian hybrid transducer head
EOU, // Real-time streaming with end-of-utterance detection
SORTFORMER // Speaker diarization (up to 4 speakers)
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ void ParakeetModel::load() {
is_loaded_ = true;

// Auto-detect modelType from the loaded GGUF's metadata. The engine
// returns "ctc" / "tdt" / "eou" / "sortformer" reflecting the
// returns "ctc" / "tdt" / "rnnt" / "eou" / "sortformer" reflecting the
// `parakeet.model.type` GGUF metadata field, so JS callers don't
// need to pass `modelType` themselves -- the binding picks the
// right dispatch (ASR vs Sortformer) automatically. We only fall
Expand All @@ -381,6 +381,7 @@ void ParakeetModel::load() {
const std::string detected = engine_->model_type();
if (detected == "ctc") cfg_.modelType = ModelType::CTC;
else if (detected == "tdt") cfg_.modelType = ModelType::TDT;
else if (detected == "rnnt") cfg_.modelType = ModelType::RNNT;
else if (detected == "eou") cfg_.modelType = ModelType::EOU;
else if (detected == "sortformer") cfg_.modelType = ModelType::SORTFORMER;

Expand Down
2 changes: 1 addition & 1 deletion packages/transcription-parakeet/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Readable } from 'stream'
* loaded GGUF's `parakeet.model.type` metadata field; this type is
* only here for callers that want to surface it in their own UI.
*/
declare type ModelType = 'tdt' | 'ctc' | 'eou' | 'sortformer'
declare type ModelType = 'tdt' | 'ctc' | 'rnnt' | 'eou' | 'sortformer'

/**
* Parakeet-specific configuration options. The model type itself is
Expand Down
2 changes: 1 addition & 1 deletion packages/transcription-parakeet/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const { END_OF_INPUT, ERR_CODES, QvacErrorAddonParakeet } = require('./lib/error
/**
* High-level Parakeet speech-to-text client backed by the ggml engine
* sourced from qvac-parakeet.cpp. Takes a single `.gguf` checkpoint
* (CTC, TDT, EOU, or Sortformer); the model type is auto-detected
* (CTC, TDT, RNNT, EOU, or Sortformer); the model type is auto-detected
* from GGUF metadata, so the same class transcribes or diarizes
* depending on the file you load.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/transcription-parakeet/parakeet.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function createParakeetError (code, message, cause = undefined) {
* runtime. Wraps the ggml-backed Parakeet engine sourced from
* qvac-parakeet.cpp. The model type is auto-detected from the
* loaded GGUF's metadata, so there's no `modelType` field on the
* config -- pass any of CTC / TDT / EOU / Sortformer .gguf files
* config -- pass any of CTC / TDT / RNNT / EOU / Sortformer .gguf files
* to `loadWeights()` and the right pipeline is chosen automatically.
*/
class ParakeetInterface {
Expand Down
Loading
Loading