Skip to content
Merged
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
dafa39f
transcriptions: windows for bounded ASR models
vasilevklart Oct 18, 2026
1f3f26a
fastconformer: shared encoder and log-mel
vasilevklart Oct 18, 2026
661c246
parakeet: Parakeet-TDT and Nemotron ASR
vasilevklart Oct 18, 2026
bb21100
canary: Canary-1B-v2
vasilevklart Oct 18, 2026
b6022c4
canary_qwen: Canary-Qwen-2.5B
vasilevklart Oct 18, 2026
6859f67
components: one encoder-decoder node for Whisper, Canary
vasilevklart Oct 18, 2026
e5be7c4
asr: review fixes on the rebased stack
vasilevklart Oct 19, 2026
2a5a89b
perf(fastconformer): plan a batch's encoder replays by cost, not one …
vasilevklart Oct 19, 2026
4066b7f
perf(fastconformer): log-mel features for the whole batch in preprocess
vasilevklart Oct 19, 2026
de91f9e
perf(fastconformer): the position term as one GEMM per head, half-ste…
vasilevklart Oct 19, 2026
25ce566
perf(fastconformer): Triton kernels for the conv module and the subsa…
vasilevklart Oct 19, 2026
11cb286
perf(fastconformer): each residual add in the kernel of the LayerNorm…
vasilevklart Oct 19, 2026
6756415
perf(fastconformer): refit the replay cost model to the fused encoder
vasilevklart Oct 19, 2026
e5689d5
docs: Omnilingual ASR gets a segment and a caption cue per window
vasilevklart Oct 21, 2026
fef8ccf
perf(transcriptions): skip the thread hop for an upload prepare() lea…
vasilevklart Oct 21, 2026
ddbce11
perf(media_io): skip the channel mean for mono audio in read_soundfil…
vasilevklart Oct 21, 2026
213ed80
Canary-Qwen: take a custom instruction from model_kwargs, not /genera…
dghosef Oct 24, 2026
515af91
Docs: untimed transcription models get one segment per window
dghosef Oct 24, 2026
7dd4d1d
Merge main into fc/asr
vasilevklart Oct 25, 2026
f0206c3
media_io: decode_audio is load_speech_file, so a missing FFmpeg stays…
vasilevklart Oct 25, 2026
e3c8d5f
fastconformer: log-mel per replay group, not padded to the batch's lo…
vasilevklart Oct 25, 2026
41187e7
canary, canary_qwen: declare their KV labels and lay out each request
vasilevklart Oct 25, 2026
bf9f067
Merge main into fc/asr
vasilevklart Oct 26, 2026
32c4258
parakeet, nemotron_asr: out of this PR, into a follow-up on top of it
vasilevklart Oct 26, 2026
6455afe
Merge main into fc/asr
vasilevklart Oct 26, 2026
323f929
RecurrentStatePool: gather / scatter_ over the step's addressing
NSagan271 Oct 26, 2026
3bf413b
test: gather / scatter_ round-trip, replay vs eager addressing, paddi…
vasilevklart Oct 26, 2026
50026aa
docs: RecurrentStatePool.gather / scatter_ are on main, not an open PR
vasilevklart Oct 26, 2026
d357820
Revert "parakeet, nemotron_asr: out of this PR, into a follow-up on t…
vasilevklart Oct 26, 2026
ceadfa5
Merge branch 'engine/recurrent-gather-scatter' into fc/transducer-loop
vasilevklart Oct 26, 2026
6fcc8c3
parakeet: the transducer as a decode loop, its state in a recurrent pool
vasilevklart Oct 26, 2026
147e524
test: the transducer loop through the recurrent pool, against #796's …
vasilevklart Oct 26, 2026
fca0849
docs: Parakeet and Nemotron keep their decoder state in a recurrent pool
vasilevklart Oct 26, 2026
7f878a0
RecurrentStatePool: gather / scatter_ refuse a pool without a sink slot
vasilevklart Oct 26, 2026
d2cb78c
Merge branch 'engine/recurrent-gather-scatter' into fc/transducer-loop
vasilevklart Oct 26, 2026
0664853
audio_features: use the engine's fp32_precision_scope for the mel matmul
dghosef Oct 26, 2026
8640efd
Merge asr/01-canary into fc/transducer-loop
dghosef Oct 26, 2026
1145f10
test: the engine's fp32_precision_scope in place of the removed helper
dghosef Oct 26, 2026
b1c4fe5
canary, canary_qwen: cap the decode loop at the request's max_output_…
dghosef Oct 26, 2026
32f38f9
transcriptions: no compression-ratio retry for the untimed ASR adapters
dghosef Oct 27, 2026
f4a9ba4
parakeet: the decode tokens reach the client from the stop check's ho…
vasilevklart Oct 27, 2026
c545b99
audio_features: only a failed decode is the upload's fault
dghosef Oct 27, 2026
6a3b19a
canary: the prompt's KV is a rows span
dghosef Oct 27, 2026
f866b4a
canary: refuse a checkpoint whose mel front end NemoLogMel doesn't co…
dghosef Oct 27, 2026
c9c7dac
token_step: say decode is uncapped with accelerator graphs off
dghosef Oct 27, 2026
cfaf667
test: load_speech_file's blame split goes through _decode, and a resa…
dghosef Oct 27, 2026
5ccd62f
canary, canary_qwen: one audio file per request, refused before decoding
dghosef Oct 27, 2026
e955a1a
asr extra installs soundfile; Higgs segments and a stale test comment…
dghosef Oct 27, 2026
18f7447
parakeet: one walk, the encoder output decoded where it lands
vasilevklart Oct 27, 2026
059f222
parakeet: 64 greedy steps a decode iteration, not 16
vasilevklart Oct 27, 2026
8155c82
parakeet: a 2,048-frame decode bucket, 164 s of audio
vasilevklart Oct 27, 2026
81038df
Merge asr/01-canary into fc/transducer-loop
dghosef Oct 27, 2026
f3233b7
TransducerAdapter: the compression-ratio opt-out now comes from _Unti…
dghosef Oct 27, 2026
3f3edfd
parakeet, nemotron_asr: one audio file per request, refused before de…
dghosef Oct 27, 2026
07b94df
Merge asr/03-transducer-loop: #890's Canary fixes under the one-walk …
vasilevklart Oct 27, 2026
6e83587
parakeet: one audio file per request, refused before decoding
vasilevklart Oct 27, 2026
0b8a741
RecurrentStatePool: gather / scatter_ read the step's plan, and gathe…
dghosef Oct 27, 2026
0e0269d
Merge asr/02-recurrent-gather-scatter into fc/transducer-loop
dghosef Oct 27, 2026
3f530e6
parakeet: read and write the transducer state through the pool's gath…
dghosef Oct 27, 2026
90caa2d
parakeet: refuse a transducer state pool with fewer than 2 slots
dghosef Oct 27, 2026
f78bb0d
parakeet: comments on the clock edge and slot lifetime match the code
dghosef Oct 27, 2026
073d7d8
docs: the recurrent state pool's gather / scatter_ for models
dghosef Oct 27, 2026
2761ca8
Merge asr/02-recurrent-gather-scatter into fc/transducer-loop
dghosef Oct 27, 2026
edf0fe6
RecurrentStatePool: say what a zero-span row addresses
dghosef Oct 27, 2026
8087a42
Merge asr/02-recurrent-gather-scatter into fc/transducer-loop
dghosef Oct 27, 2026
4e2901c
parakeet: drop the stop check's copy of the loop cap
dghosef Oct 27, 2026
4e09fcc
test: drop the frozen copy of the transducer step; the independent re…
dghosef Oct 27, 2026
7f49c53
RecurrentStatePool: cast the scatter index once per step
dghosef Oct 27, 2026
d6972da
Merge asr/02-recurrent-gather-scatter into fc/transducer-loop
dghosef Oct 27, 2026
dac3163
Merge asr/03-transducer-loop (one-walk loop, 64-step chunk, 2048 buck…
dghosef Oct 27, 2026
e5f4cd5
Merge main into asr/03-transducer-loop
vasilevklart Oct 27, 2026
9329535
Merge main into asr/03-transducer-loop
vasilevklart Oct 27, 2026
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
2 changes: 1 addition & 1 deletion .claude/skills/engine-resources/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Entries marked *open PR* are not on `main` yet. Check the checkout; if your port
| | `RaggedCrossAttentionSpec` | one contiguous key range per query segment |
| | `RaggedBlockCausalAttentionSpec` (#381, *open PR*) | each block attends its span's prefix of blocks |
| a fixed-size cache per request: a sink plus a sliding window, optionally after a shared read-only prefix | bounded KV (`BoundedKVSpec`, #383, *open PR*) | rows at any position in one batch; per-row source; a per-distance score term |
| fixed-size opaque state per request (recurrent, conv tails) | `RecurrentStatePool` | slots read and written through the step's addressing (`gather` / `scatter_`, #383, *open PR*) |
| fixed-size opaque state per request (recurrent, conv tails) | `RecurrentStatePool` | slots read and written through the step's addressing (`gather` / `scatter_`) |
| frame rings (Waypoint) | `RingKVManager` | to be merged into bounded KV |

A resource that holds per-request state gives models operations driven by the step (`gather` / `scatter_`, `attend` over the current plan). It never asks a model to index its storage or to hold and select rows of its plans.
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ For example, nothing under `mstar/model/` should:
- **Allocate, free, or evict resource state.** No calls into `PageArena`, `PageAllocator`, `CacheStream`, `CPUPagePool`, or `WorkspacePool`, and no direct `admit`/`commit`. Declare resources in `Model.get_node_resources()` and declare each step's effect on them in `NodeSubmodule.declare_step()`. The engine runs the lifecycle.
- **Choose which requests form a batch.** Batch *selection* is the micro-scheduler's job: implement `can_batch` and `forward_batched`, set `input_seq_len` in `prepare_inputs`, and let it decide. (Note: given a batch, mechanically stacking or concatenating tensors in `preprocess` is normal and expected, and some audio submodules also pad to a maximum sequence length themselves for capture compatibility).
- **Manage streams or synchronize.** No `torch.Stream`, `torch.Event`, `torch.accelerator.synchronize`, or device-specific equivalents under `mstar/model/`.
- **Index a resource's storage or hold its plans.** No `pool.block(...).index_select` / `index_copy_`, host-side slot lookups, or keeping `resource.current` to select rows from later. The resource exposes the access, driven by the step (e.g., `RecurrentStatePool.gather` / `scatter_` ([#383](https://github.com/mstar-project/mstar/pull/383), open PR), `attend` over the current plan), so eager and captured paths address rows the same way.
- **Index a resource's storage or hold its plans.** No `pool.block(...).index_select` / `index_copy_`, host-side slot lookups, or keeping `resource.current` to select rows from later. The resource exposes the access, driven by the step (e.g., `RecurrentStatePool.gather` / `scatter_`, `attend` over the current plan), so eager and captured paths address rows the same way.

Things that look model-specific but belong to the system:

Expand Down
7 changes: 5 additions & 2 deletions benchmark/asr_eval.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""ASR evaluation script: compute Word Error Rate (WER) on LibriSpeech test-clean.

Runs inference against a running mstar server and compares transcription output
against ground-truth transcripts. Supports Whisper-large-v3 and Higgs Audio.
against ground-truth transcripts, for the models in ``_ASR_MODELS``.

Usage:
python -m benchmark.asr_eval \\
Expand All @@ -27,7 +27,10 @@
from benchmark.dataset import LibriSpeechEvalDataset
from benchmark.request import RequestInput

_ASR_MODELS = {ModelType.WHISPER_LARGE, ModelType.HIGGS_AUDIO}
_ASR_MODELS = {
ModelType.WHISPER_LARGE, ModelType.HIGGS_AUDIO,
ModelType.CANARY, ModelType.CANARY_QWEN, ModelType.PARAKEET, ModelType.NEMOTRON_ASR,
}


async def _transcribe(
Expand Down
39 changes: 39 additions & 0 deletions benchmark/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,33 @@ def get_model_kwargs(self, request_type: RequestType):
}


class _FastConformerAsr(Model):
"""NVIDIA's FastConformer speech recognizers: audio in, a transcript out, greedy."""

def get_supported_modalities(self):
return {RequestType.A2T}


class Canary(_FastConformerAsr):
def get_hf_url(self):
return "nvidia/canary-1b-v2"


class CanaryQwen(_FastConformerAsr):
def get_hf_url(self):
return "nvidia/canary-qwen-2.5b"


class Parakeet(_FastConformerAsr):
def get_hf_url(self):
return "nvidia/parakeet-tdt-0.6b-v3"


class NemotronAsr(_FastConformerAsr):
def get_hf_url(self):
return "nvidia/nemotron-3.5-asr-streaming-0.6b"


class ModelType(Enum):
BAGEL = "bagel"
ORPHEUS = "orpheus"
Expand All @@ -431,6 +458,10 @@ class ModelType(Enum):
VJEPA2AC = "vjepa2ac"
WHISPER_LARGE = "whisper_large"
HIGGS_AUDIO = "higgs_audio"
CANARY = "canary"
CANARY_QWEN = "canary_qwen"
PARAKEET = "parakeet"
NEMOTRON_ASR = "nemotron_asr"
QWEN3_5 = "qwen3.5"
QWEN3_8 = "qwen3.8"

Expand Down Expand Up @@ -459,6 +490,14 @@ def inst(self, **kwargs) -> Model:
return WhisperLarge(**kwargs)
if self == ModelType.HIGGS_AUDIO:
return HiggsAudio(**kwargs)
if self == ModelType.CANARY:
return Canary(**kwargs)
if self == ModelType.CANARY_QWEN:
return CanaryQwen(**kwargs)
if self == ModelType.PARAKEET:
return Parakeet(**kwargs)
if self == ModelType.NEMOTRON_ASR:
return NemotronAsr(**kwargs)
if self == ModelType.QWEN3_5:
return Qwen3_5_Dense(**kwargs)
if self == ModelType.QWEN3_8:
Expand Down
11 changes: 6 additions & 5 deletions benchmark/run_asr_benchmark.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# ASR benchmark script: throughput and latency for Whisper-large-v3 and Higgs Audio.
# ASR benchmark script: throughput and latency for the ASR models below.
#
# Usage:
# ./benchmark/run_asr_benchmark.sh --url http://localhost:8000 [options]
Expand All @@ -11,7 +11,8 @@
# --url <base_url> mstar server base URL
#
# Optional:
# --model <name> Run only this model (whisper_large|higgs_audio)
# --model <name> Run only this model (whisper_large|higgs_audio|canary|
# canary_qwen|parakeet|nemotron_asr)
# --num-requests <n> Total requests per model (default: 100)
# --batch-size <b> Batch size for offline profiling (default: 4)
# --max-concurrency <c> Concurrency cap for closed-loop profiling (default: 4)
Expand Down Expand Up @@ -52,7 +53,7 @@ if [[ -z "$URL" ]]; then
exit 1
fi

ASR_MODELS=(whisper_large higgs_audio)
ASR_MODELS=(whisper_large higgs_audio canary canary_qwen parakeet nemotron_asr)

if [[ -n "$MODEL" ]]; then
ASR_MODELS=("$MODEL")
Expand Down Expand Up @@ -101,14 +102,14 @@ done
echo ""
echo "All ASR benchmarks complete. Results in: ${OUTPUT_DIR}"

# Print a quick comparison table if all three models ran
# Print a quick comparison table of the models that ran
if [[ -z "$MODEL" ]] && command -v python &>/dev/null; then
export _ASR_OUTPUT_DIR="$OUTPUT_DIR"
python - <<'PYEOF'
import json, os, sys

output_dir = os.environ.get("_ASR_OUTPUT_DIR", "./asr_benchmark_results")
models = ["whisper_large", "higgs_audio"]
models = ["whisper_large", "higgs_audio", "canary", "canary_qwen", "parakeet", "nemotron_asr"]

rows = []
for m in models:
Expand Down
14 changes: 14 additions & 0 deletions configs/canary.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
model: "canary"
max_seq_len: 1024
# The decoder caches hold 64 requests at their limits (4 context pages for a
# 40.96 s clip, 8 self-attention pages at the position limit), plus the page
# each cache keeps as its sink.
max_concurrent_requests: 64
resources:
kv_cache:
max_num_pages: 513
cross_kv_cache:
max_num_pages: 257
node_groups:
- node_names: [audio_encoder, decoder]
ranks: [0]
11 changes: 11 additions & 0 deletions configs/canary_qwen.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
model: "canary_qwen"
max_seq_len: 2048
# The KV cache holds 64 requests at max_seq_len (16 pages each) plus its sink
# page; the conductor queues the rest rather than have the worker offload.
max_concurrent_requests: 64
resources:
kv_cache:
max_num_pages: 1025
node_groups:
- node_names: [audio_encoder, llm]
ranks: [0]
17 changes: 17 additions & 0 deletions configs/nemotron_asr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
model: "nemotron_asr"
max_seq_len: 8192
# A request holds one decoder state slot from its first decode iteration until
# it is torn down; the pool holds max_concurrent_requests of them plus its sink
# slot, and the conductor queues the rest.
max_concurrent_requests: 128
resources:
transducer_state:
max_slots: 129
node_groups:
- node_names: [audio_encoder, transducer]
ranks: [0]
# Constructor options (forwarded to ParakeetModel.__init__):
# model_kwargs:
# lookahead: 13 # right attention context in 80 ms frames: 0, 3, 6 or 13;
# # wider is more accurate, and the widest is the default
# compile_step: false # decode with eager kernels: start-up a few seconds faster, decoding ~2.5x slower
15 changes: 15 additions & 0 deletions configs/parakeet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
model: "parakeet"
max_seq_len: 8192
# A request holds one decoder state slot from its first decode iteration until
# it is torn down; the pool holds max_concurrent_requests of them plus its sink
# slot, and the conductor queues the rest.
max_concurrent_requests: 128
resources:
transducer_state:
max_slots: 129
node_groups:
- node_names: [audio_encoder, transducer]
ranks: [0]
# Constructor options (forwarded to ParakeetModel.__init__):
# model_kwargs:
# compile_step: false # decode with eager kernels: start-up a few seconds faster, decoding ~2.5x slower
22 changes: 20 additions & 2 deletions docs/adding_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,18 @@ The spec types are:
``enable_min_p``, ``max_repetition_window``, ``min_tokens_stop_ids`` and
``enable_top_p_first`` are capabilities of the same kind. See
``SamplingReqConfig`` above.
* - ``RecurrentStateSpec(config=RecurrentStateConfig(...))``
- Fixed-size per-request state that carries between steps (an LSTM's ``h`` and
``c``, a cursor, a conv tail): one slot per request, ``blocks`` naming a shape and
dtype for each piece, ``num_layers`` copies of each, ``max_slots`` slots with slot 0
the sink that padding rows address. ``declare_step`` gives each row a
``RecurrentStep`` segment with span >= 1. The forward reads its rows with
``pool.gather(name, start=...)`` and writes them back with
``pool.scatter_(name, value)``; both follow the step's plan, so there is no
addressing to fetch, and eager and captured steps reach the same slots. A row with
no saved state (a request's first step, or a padding row) reads ``start``, zeros
when none is given. ``gather`` / ``scatter_`` need the sink, so leave
``disable_sink_slot`` unset. Parakeet's transducer decode is the example.

Orpheus declares four specs for its one autoregressive node. Its ``snac_decoder`` node
appears in no spec, so it receives no resources:
Expand Down Expand Up @@ -621,6 +633,9 @@ appears in no spec, so it receives no resources:
* - Decoder of an encoder-decoder model
- The three or four specs above, plus a second ``KVSpec`` for the encoder context
and a ``CrossAttentionSpec`` over that second cache.
* - A node that carries per-request state between steps of a loop (an RNN-T
decoder, recurrent attention)
- A ``RecurrentStateSpec``, read and written with ``gather`` / ``scatter_``.
* - A node that samples with two different sets of parameters
- Two ``SamplerSpec`` objects that both name the node, under different keys.
* - An encoder tower that attends within the segments of one packed forward
Expand Down Expand Up @@ -2025,9 +2040,12 @@ Sizing the caches is only half of it: ``configs/whisper_large.yaml`` also sets
``max_concurrent_requests: 64``, so the conductor queues further requests instead of the
worker offloading decoding requests to admit them. ``WhisperModel.validate_config_yaml``
refuses at startup a cap that either cache cannot hold after the YAML's ``resources:``
overrides.
overrides, through ``mstar.model.utils.check_kv_pools_fit``, which any model with KV caches
can call the same way.

Whisper's ``declare_step`` shows how a write-once context is expressed with spans. The
The decoder node's ``declare_step`` shows how a write-once context is expressed with spans.
It lives in ``EncoderDecoderNode`` (``mstar/model/components/encoder_decoder.py``), which
Whisper's and Canary's decoder nodes share; Whisper adds only its token suppression. The
context segments have a non-zero span in the prefill step that writes them, and a span of
0 in every later step. The ``commit`` in the prefill step converts the reservation into
resident pages that the later steps read.
Expand Down
18 changes: 15 additions & 3 deletions docs/clients.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,8 @@ Endpoints and model coverage:
- speech models that publish a voice list through their speech adapter (``kokoro``, ``orpheus``; 404 otherwise)
- The ``voice`` ids the served model accepts, plus its default.
* - ``POST /v1/audio/transcriptions``
- ``whisper_large``, ``higgs_audio``, ``omnilingual_asr_ctc_*``
- ``whisper_large``, ``higgs_audio``, ``omnilingual_asr_ctc_*``, ``canary``, ``canary_qwen``, ``parakeet``,
``nemotron_asr``
- Speech-to-text (multipart upload; ``json`` / ``text`` / ``verbose_json`` /
``srt`` / ``vtt``; streaming via ``transcript.text.delta`` events).
* - ``WS /v1/realtime?intent=transcription``
Expand Down Expand Up @@ -302,7 +303,9 @@ Per-model notes:
``initial_prompt``), and ``response_format``
``verbose_json`` / ``srt`` / ``vtt`` (or ``timestamp_granularities[]``) asks the
model for timestamps. Whisper's language and timestamp tokens travel in the
text stream and are lifted into ``language`` / ``segments`` by the server; a
text stream and are lifted into ``language`` / ``segments`` by the server;
Higgs-Audio emits no timestamps, so its ``verbose_json`` / ``srt`` / ``vtt`` get
one segment per window, timed to the windows. A
streaming client receives only the spoken words. Uploads longer than the
model's clip (30 s for Whisper) are served as consecutive windows. By default
they run in order, openai-whisper style: each window gets the transcript so
Expand All @@ -326,8 +329,17 @@ Per-model notes:
clip of up to 20 s is one request; a longer upload is cut into windows of about equal
length, at most 16 s, at quiet points and transcribed in parallel (``window_seconds``
in ``extra_body``, 5 to 40, sets both lengths). There are no timestamps: ``srt`` / ``vtt``
get one cue spanning the file. Nothing detects the language: ``verbose_json``'s
get one cue per window, timed to the windows. Nothing detects the language: ``verbose_json``'s
``language`` is the request's ``language`` as given, or null.
- **Canary / Canary-Qwen / Parakeet / Nemotron ASR** — no conditioning text (``prompt`` is
dropped) and no timestamps: ``timestamp_granularities`` is a 400, and ``srt`` / ``vtt`` /
``verbose_json`` get one segment per window. Canary takes ``language`` (the speech's,
English by default) and, through ``extra_body``, ``target_language`` or
``task="translate"`` (into English) and ``punctuation``; the other three only transcribe,
and refuse a ``task`` other than ``transcribe``. Canary-Qwen is English only. Parakeet detects the language itself and refuses a ``language`` outside the 25 it knows;
Nemotron takes a locale (``en-US``), a bare code or ``auto``. Uploads longer than the
model's clip (40 s for Canary and Canary-Qwen, 10 min for Parakeet and Nemotron) run as
parallel windows.
- **Realtime transcription** — every ``chunk_seconds`` (default 2 s) of new audio the
session re-transcribes everything heard so far as one engine request whose assistant
turn is prefilled with the previous hypothesis minus its last ``unfixed_tokens``
Expand Down
6 changes: 6 additions & 0 deletions docs/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ Model families and some output formats need extra packages, exposed as pip *extr
package metadata allows ``m-star`` to be published on PyPI. **Also needs**
``flash-attn-4``, which is installed separately —
see `flash-attn-4 (Waypoint, FA3 sm90 kernel)`_.
* - ``.[asr]``
- Speech recognition models: ``transformers``, ``flashinfer-python``, ``safetensors``,
``einops``, ``soundfile`` (WAV / FLAC / OGG / MP3 uploads), ``torchcodec``
(FFmpeg-backed decoding of the other formats), ``huggingface-hub``,
``mooncake-transfer-engine``, and ``datasets`` / ``jiwer`` for
``benchmark/asr_eval.py``.
* - ``.[audio]``
- ``soundfile`` — only needed to return **non-WAV** audio containers (mp3/flac/…)
from the OpenAI/SDK audio surfaces. WAV/PCM output works without it.
Expand Down
Loading
Loading