Skip to content
Merged
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
6 changes: 2 additions & 4 deletions examples/bench/batch_bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@
//
// Loads a model + session ONCE, then times transcribe_run_batch over a
// sweep of batch sizes, reporting per-utterance latency and wall time per
// batch. This is the committed replacement for the throwaway harness that
// produced reports/perf/l40s/parakeet-batch/*.json — it measures only the
// compute (model load is excluded), so per_utt_ms is directly comparable
// batch. Model load is excluded, so per_utt_ms is directly comparable
// across batch sizes.
//
// The batch is built by repeating a single input clip N times, which
// isolates the device-occupancy effect of batching from input-length
// variance. (Real workloads vary; this is a controlled throughput probe,
// not a WER measurement.) Output is a JSON array on stdout, one object per
// batch size, matching the historical schema so existing plots keep working.
// batch size.
//
// Usage:
// transcribe-batch-bench -m model.gguf clip.wav \
Expand Down
40 changes: 10 additions & 30 deletions examples/cli/main.cpp
Original file line number Diff line number Diff line change
@@ -1,23 +1,9 @@
// transcribe-cli - example CLI driver for transcribe.cpp
//
// Pass 2 stub: this CLI exercises the public ABI end-to-end with the
// stub library. It loads a WAV file (must be 16 kHz mono float32 source
// or downmixable to mono), prints duration / sample count, optionally
// asks the library to load a model (which will return NOT_IMPLEMENTED
// in pass 2), and prints the resulting status string.
//
// Once the loader and decoder land, this same CLI will run real
// transcription. Argument parsing, log sink wiring, and result printing
// will grow in place rather than being rewritten.
//
// Usage:
// transcribe-cli [options] audio.wav
// Options:
// -m, --model PATH GGUF model file (optional in pass 2)
// -l, --language ISO BCP-47-ish language hint (e.g. en, de)
// -t, --translate set task to TRANSLATE
// -q, --quiet suppress library log output
// -h, --help show this help
// Loads a 16 kHz mono float32 WAV (or downmixable to mono), loads a GGUF
// model, and transcribes it through the public ABI. Supports single-file
// and batch modes, offline and streaming paths, and per-family knobs.
// Run with --help for the full option list.

#include "transcribe.h"
#include "transcribe/parakeet.h"
Expand Down Expand Up @@ -555,18 +541,16 @@ int main(int argc, char ** argv) {
transcribe_log_set(log_cb, nullptr);
}

// ---- Batch mode: --batch reads a file list, one wav path per
// line. Loads the model ONCE and reuses the context across all
// files. Outputs one JSONL line per file to stdout when
// --batch-jsonl is set, otherwise the same human-readable format
// as single-file mode. ------------------------------------------------
// Batch mode: --batch reads a file list, one wav path per line. Loads
// the model ONCE and reuses the context across all files. Outputs one
// JSONL line per file to stdout when --batch-jsonl is set, otherwise
// the same human-readable format as single-file mode.
if (!args.batch_file.empty()) {
if (args.model_path.empty()) {
std::fprintf(stderr, "error: --batch requires --model\n");
return EXIT_FAILURE;
}

// Read the file list.
std::vector<std::string> wav_paths;
{
std::ifstream fin(args.batch_file);
Expand All @@ -577,7 +561,6 @@ int main(int argc, char ** argv) {
}
std::string line;
while (std::getline(fin, line)) {
// Trim trailing whitespace / carriage return.
while (!line.empty() &&
(line.back() == '\n' || line.back() == '\r' ||
line.back() == ' ' || line.back() == '\t'))
Expand All @@ -597,7 +580,6 @@ int main(int argc, char ** argv) {
std::fprintf(stderr, "batch: %zu files\n", wav_paths.size());
}

// Load model once.
struct transcribe_model_load_params mp; transcribe_model_load_params_init(&mp);
mp.backend = args.backend;
mp.gpu_device = args.gpu_device;
Expand All @@ -610,7 +592,6 @@ int main(int argc, char ** argv) {
return EXIT_FAILURE;
}

// Init context once (reused across all files via run()).
struct transcribe_session_params cp; transcribe_session_params_init(&cp);
cp.n_threads = args.n_threads;
cp.n_ctx = args.n_ctx;
Expand Down Expand Up @@ -801,7 +782,6 @@ int main(int argc, char ** argv) {
for (size_t i = 0; i < wav_paths.size(); ++i) {
const std::string & wav = wav_paths[i];

// Load wav.
std::vector<float> pcm;
std::string wav_err;
if (!transcribe_cli::load_wav_mono_16k(wav, pcm, wav_err)) {
Expand Down Expand Up @@ -931,7 +911,7 @@ int main(int argc, char ** argv) {
}
std::fflush(stdout);
}
} // end serial else
}

if (!args.batch_jsonl) {
std::fprintf(stderr, "batch: %d ok, %d failed out of %zu\n",
Expand All @@ -943,7 +923,7 @@ int main(int argc, char ** argv) {
return n_fail > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

// ---- Single-file mode (original path). -----------------------------
// Single-file mode.
std::vector<float> pcm;
std::string load_err;
if (!transcribe_cli::load_wav_mono_16k(args.wav_path, pcm, load_err)) {
Expand Down
2 changes: 1 addition & 1 deletion examples/common/wav.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Loads a RIFF WAV file as mono float32 PCM at 16 kHz, which is the only
// input format the v1 transcribe runtime accepts. The WAV loader does NOT
// resample. Files at any other sample rate are rejected with a message
// pointing the user at sox/ffmpeg, per PLAN.md "Sample Rate Policy".
// pointing the user at sox/ffmpeg.
//
// This file lives under examples/common/ on purpose: dr_wav and the WAV
// loader are not part of the runtime library. The core library never
Expand Down
100 changes: 35 additions & 65 deletions include/transcribe.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,20 @@
* single startup-time install only.
* - Calling transcribe_log_set() after threads or models exist is
* UNSUPPORTED in 0.x. The implementation is data-race-free (the two
* atomics ensure no torn reads), but the API does NOT guarantee any
* of the following under concurrent or mid-run reconfiguration:
* (a) pair-atomic publication of (callback, userdata) - an emitter
* may observe a callback from one generation paired with a
* userdata from another, especially if two threads call
* transcribe_log_set concurrently;
* (b) that the old callback or old userdata will not be invoked
* after transcribe_log_set returns - an in-flight emission on
* another thread may already be holding the previous pair on
* its stack and about to call through it.
* A caller that needs mid-run reconfiguration must provide its own
* external synchronization between transcribe_log_set callers AND
* keep every previous callback target and userdata alive until it
* can prove no thread can still emit with them. A future revision
* may add a properly synchronized reconfiguration entry point with
* stronger guarantees.
* atomics ensure no torn reads), but under concurrent or mid-run
* reconfiguration the API does NOT guarantee pair-atomic publication
* of (callback, userdata), nor that the previous callback/userdata
* will not still be invoked after transcribe_log_set returns (an
* in-flight emission on another thread may already hold the old pair).
* A caller that needs mid-run reconfiguration must externally
* synchronize transcribe_log_set callers AND keep every previous
* callback target and userdata alive until no thread can still emit
* with them.
*
* ABI stability (0.x):
* - This library is pre-1.0. The on-disk ABI MAY break between 0.x minor
* releases. Consumers should rebuild against matching headers and
* should not assume any layout, enum value, or symbol set is frozen.
* The `struct_size` mechanism described below is forward-ABI scaffolding
* we will lean on for the post-1.0 stable surface; treat it as a
* compatibility hook in the making, not a stability promise today.
*
* Params (size-aware structs):
* - Every caller-owned public struct crossing the ABI carries `struct_size`
Expand Down Expand Up @@ -208,12 +198,7 @@ typedef enum {
TRANSCRIBE_ERR_UNSUPPORTED_VARIANT = 6,
TRANSCRIBE_ERR_OOM = 7,
TRANSCRIBE_ERR_BACKEND = 8,
/*
* Reserved. v1 accepts only 16 kHz mono float32 PCM and the library
* does not link a resampler, so there is currently no caller-supplied
* sample rate to validate. This code is preserved at its assigned
* value for the future "caller declares input rate" entry point.
*/
/* Reserved; not currently returned. */
TRANSCRIBE_ERR_SAMPLE_RATE = 9,
TRANSCRIBE_ERR_UNSUPPORTED_LANGUAGE = 10,
TRANSCRIBE_ERR_UNSUPPORTED_TASK = 11,
Expand Down Expand Up @@ -244,21 +229,9 @@ typedef enum {
* transcribe_*_init function" specifically.
*/
TRANSCRIBE_ERR_BAD_STRUCT_SIZE = 14,
/*
* Reserved. Phase 2 ships warn-and-proceed semantics for
* transcribe_run_params::pnc: a non-DEFAULT value against a model that
* does not advertise transcribe_model_supports(model, TRANSCRIBE_FEATURE_PNC)
* emits a WARN-level log message and proceeds with the model's
* default behavior. This code is preserved at its assigned value
* for a future opt-in strict-advisory mode in which the dispatcher
* would return this code instead of warning. Not currently
* returned.
*/
/* Reserved; not currently returned. */
TRANSCRIBE_ERR_UNSUPPORTED_PNC = 15,
/*
* Reserved. Symmetric with TRANSCRIBE_ERR_UNSUPPORTED_PNC for
* transcribe_run_params::itn. Not currently returned.
*/
/* Reserved; not currently returned. */
TRANSCRIBE_ERR_UNSUPPORTED_ITN = 16,
/*
* Returned by transcribe_run / transcribe_run_batch when the input
Expand Down Expand Up @@ -494,9 +467,9 @@ typedef enum {
* Each family that exposes a runtime PNC toggle reads this field; families
* that do not (whisper, parakeet, ...) ignore it. The dispatcher emits a
* WARN-level log message when a non-DEFAULT value is set against a model
* whose capabilities advertise supports_pnc == false, then proceeds with
* the model's default behavior. Use transcribe_capabilities::supports_pnc
* to pre-check.
* for which transcribe_model_supports(model, TRANSCRIBE_FEATURE_PNC)
* returns false, then proceeds with the model's default behavior. Use
* that probe to pre-check.
*
* DEFAULT (0): the family's shipped default. Zero-init via
* transcribe_run_params_init() gives this value. The family
Expand All @@ -522,8 +495,9 @@ enum transcribe_pnc_mode {
* transformation that renders numbers, dates, currencies, etc. in formal
* form ("twenty twenty four" → "2024", "ten dollars" → "$10"). Each
* family that exposes a runtime ITN toggle reads this field; families
* that do not ignore it. Non-DEFAULT values against
* supports_itn == false emit a WARN and proceed with default behavior.
* that do not ignore it. Non-DEFAULT values against a model for which
* transcribe_model_supports(model, TRANSCRIBE_FEATURE_ITN) returns false
* emit a WARN and proceed with default behavior.
*
* DEFAULT (0): family default. Zero-init gives this value.
* OFF: explicit ITN off. Supporting families emit verbatim
Expand Down Expand Up @@ -993,13 +967,17 @@ TRANSCRIBE_API void transcribe_session_params_init(
*
* pnc: punctuation+capitalization runtime toggle. See
* transcribe_pnc_mode. DEFAULT is always safe. Non-DEFAULT
* values against models with supports_pnc == false emit a
* WARN and proceed with the model's default behavior.
* values against models for which
* transcribe_model_supports(model, TRANSCRIBE_FEATURE_PNC) is
* false emit a WARN and proceed with the model's default
* behavior.
*
* itn: inverse text normalization runtime toggle. See
* transcribe_itn_mode. DEFAULT is always safe. Non-DEFAULT
* values against models with supports_itn == false emit a
* WARN and proceed with the model's default behavior.
* values against models for which
* transcribe_model_supports(model, TRANSCRIBE_FEATURE_ITN) is
* false emit a WARN and proceed with the model's default
* behavior.
*
* language: source language hint as a BCP-47-ish short code, or
* NULL to autodetect (only if the model supports it).
Expand Down Expand Up @@ -1110,10 +1088,6 @@ TRANSCRIBE_API void transcribe_run_params_init(
* anything similar in the future) live behind the
* transcribe_model_supports() probe, keyed by transcribe_feature.
* A new feature is +1 enum value with no struct_size churn.
*
* Trajectory note: revisit this shape if the bool cluster in the
* struct grows past ~5 or if a plugin-like family ABI is introduced.
* Neither condition is in flight today.
*/
struct transcribe_capabilities {
uint64_t struct_size;
Expand Down Expand Up @@ -1368,8 +1342,7 @@ TRANSCRIBE_API const char * transcribe_model_meta_val_str(
/* ----------------------------------------------------------------------- */

/*
* Load a GGUF model from disk. The _file suffix is preserved to leave
* room for transcribe_model_load_buffer() later without renaming.
* Load a GGUF model from disk.
*
* params may be NULL for all library defaults. To customize, initialize
* a struct with transcribe_model_load_params_init() and set fields. A
Expand Down Expand Up @@ -1445,11 +1418,10 @@ TRANSCRIBE_API transcribe_status transcribe_open(
struct transcribe_session ** out_session);

/*
* Deprecated alias for transcribe_session_free, kept for source
* compatibility with the prior split open/close shape. Both honor
* owns_model and free the owned model when present, so a caller may use
* either with any session. New code should call transcribe_session_free
* directly. Passing NULL is a no-op.
* Deprecated alias for transcribe_session_free. Both honor owns_model and
* free the owned model when present, so a caller may use either with any
* session. New code should call transcribe_session_free directly. Passing
* NULL is a no-op.
*/
TRANSCRIBE_API void transcribe_close(struct transcribe_session * session);

Expand Down Expand Up @@ -2046,7 +2018,7 @@ TRANSCRIBE_API transcribe_status transcribe_stream_get_text(
* run_params->language not in the
* model's declared language list.
*
* Failure semantics — three stages, split by whether the previous
* Failure semantics — three checkpoints, split by whether the previous
* result snapshot survives:
*
* 1. Dispatcher preflight. Top-level argument checks run first:
Expand All @@ -2066,9 +2038,9 @@ TRANSCRIBE_API transcribe_status transcribe_stream_get_text(
* result snapshot fully preserved and no FAILED transition, so a
* caller-side config typo cannot destroy the prior utterance's
* transcript. A family that does not implement stream_validate
* defers these checks to stage 3.
* performs these checks in stream_begin.
*
* 3. Post-clear stream_begin. Once stages 1-2 pass, the dispatcher
* 3. Post-clear stream_begin. Once the preflight checks pass, the dispatcher
* clears the result snapshot, enters ACTIVE, and calls the
* family's stream_begin hook. Any non-OK status from this point
* (config a non-preflighting family only catches here, allocation
Expand Down Expand Up @@ -2255,9 +2227,7 @@ TRANSCRIBE_API int transcribe_tokenize(
* encode_ms time to run the encoder forward pass on the most recent
* transcribe_run.
* decode_ms time to run the decoder (predictor + joint + token
* search) on the most recent transcribe_run. Currently
* always 0 since the decoder isn't wired yet; phase 5
* fills this in.
* search) on the most recent transcribe_run.
*
* Output struct: caller initializes via transcribe_timings_init() (zero-
* fill); the library writes only the fields that fit within
Expand Down
5 changes: 3 additions & 2 deletions include/transcribe/whisper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
*
* Whisper exposes substantial real model-specific knobs (13 fields).
* The PNC/ITN toggles that other families share via transcribe_run_params
* do not apply: whisper does not advertise supports_pnc / supports_itn,
* and a non-DEFAULT pnc/itn against a whisper model produces a WARN.
* do not apply: transcribe_model_supports(model, TRANSCRIBE_FEATURE_PNC)
* and (..., TRANSCRIBE_FEATURE_ITN) both return false for whisper, and a
* non-DEFAULT pnc/itn against a whisper model produces a WARN.
* Probe via transcribe_model_accepts_ext_kind before pointing
* transcribe_run_params::family at this struct.
*
Expand Down
28 changes: 6 additions & 22 deletions src/arch/canary/canary.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,8 @@
// arch/canary/canary.h - Canary multitask AED model and context types.
//
// This header is INTERNAL to src/arch/canary/. It defines the concrete
// classes that derive from transcribe_model / transcribe_session for
// the NVIDIA Canary family (FastConformer encoder + Transformer decoder
// with 4-slot or 5-slot multitask prompt).
//
// Modeled on src/arch/cohere/cohere.h. Differences from cohere:
// - encoder shape mirrors parakeet's FastConformer, but every linear
// (Q/K/V/out, both macaron FFs, attention-pos projection, conv
// pointwise pair) carries a bias term. Parakeet is bias-free;
// canary is NOT. See weights.cpp for the full bias catalog.
// - decoder is structurally identical to cohere's but tensor names
// differ (dec.layer.{i}.norm{1,2,3} / {self_attn,cross_attn,ffn}.{q,k,v,o,up,down})
// - LM head is UNTIED (explicit dec.head.{weight,bias})
// - 180m-flash variant has an encoder->decoder projection
// (enc_d_model=512 -> dec_d_model=1024); other variants share
// d_model and skip the projection
// NVIDIA Canary: FastConformer encoder (parakeet shape but with biases on
// every linear) + autoregressive Transformer decoder (untied LM head;
// 180m-flash adds an enc->dec projection) with a 4/5-slot multitask prompt.

#pragma once

Expand Down Expand Up @@ -149,12 +136,9 @@ struct CanarySession final : public transcribe_session {
std::vector<float> enc_host;


// Per-stage flash-attention controls. Same rationale as cohere:
// encoder rel-pos MHSA dk depends on enc_d_model/n_heads (96 for
// 180m-flash, 128 for the larger variants); decoder dk=128
// uniformly. ggml's Metal flash kernel currently lacks a path for
// some encoder dk values, so we default encoder flash off on
// Metal. The decoder defaults flash on.
// Per-stage flash-attention controls. ggml's Metal flash kernel lacks a
// path for some encoder rel-pos MHSA dk values (96 for 180m-flash, 128
// otherwise), so encoder flash defaults off on Metal; decoder defaults on.
bool encoder_use_flash = true;
bool decoder_use_flash = true;

Expand Down
6 changes: 2 additions & 4 deletions src/arch/canary/capabilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ void apply_family_invariants(transcribe_model & model) {
// directions are an optional GGUF contract in stt.translation.pairs.
caps.supports_translate = true;

// V1 port: timestamps are explicitly experimental upstream and
// out of scope (per intake known_risks). Advertise NONE; the GGUF
// KV stt.capability.timestamps overrides this when a future port
// wires up the timestamp decoder path.
// Timestamps out of scope. Advertise NONE; the GGUF KV
// stt.capability.timestamps overrides this once the path is wired up.
caps.max_timestamp_kind = TRANSCRIBE_TIMESTAMPS_NONE;

// Feature bits: cancellation is wired at the run level. Canary
Expand Down
Loading
Loading