Skip to content
Open
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: 3 additions & 3 deletions bindings/python/src/transcribe_cpp/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# Stable digest of the ABI surface below (structs, enums, macros, layout,
# prototypes). A native provider package echoes this back so the API
# package can reject an ABI-mismatched provider before dlopen.
PUBLIC_HEADER_HASH = "7df72bf9e667b8c2"
PUBLIC_HEADER_HASH = "8622da005d6a6fcc"

# === enum constants ===
TRANSCRIBE_OK = 0
Expand Down Expand Up @@ -167,7 +167,7 @@ class transcribe_whisper_chunk_trace(_c.Structure):
transcribe_device_info._fields_ = [("struct_size", _c.c_uint64), ("name", _c.c_char_p), ("description", _c.c_char_p), ("kind", _c.c_char_p), ("device_id", _c.c_char_p), ("memory_total", _c.c_uint64), ("memory_free", _c.c_uint64), ("device_type", _c.c_int)]
transcribe_model_load_params._fields_ = [("struct_size", _c.c_uint64), ("backend", _c.c_int), ("device", _c.c_void_p)]
transcribe_session_params._fields_ = [("struct_size", _c.c_uint64), ("n_threads", _c.c_int), ("kv_type", _c.c_int), ("n_ctx", _c.c_int32)]
transcribe_run_params._fields_ = [("struct_size", _c.c_uint64), ("task", _c.c_int), ("timestamps", _c.c_int), ("pnc", _c.c_int), ("itn", _c.c_int), ("diarize", _c.c_int), ("language", _c.c_char_p), ("target_language", _c.c_char_p), ("keep_special_tags", _c.c_bool), ("family", _c.POINTER(transcribe_ext)), ("spec_k_drafts", _c.c_int32)]
transcribe_run_params._fields_ = [("struct_size", _c.c_uint64), ("task", _c.c_int), ("timestamps", _c.c_int), ("pnc", _c.c_int), ("itn", _c.c_int), ("diarize", _c.c_int), ("language", _c.c_char_p), ("target_language", _c.c_char_p), ("keep_special_tags", _c.c_bool), ("family", _c.POINTER(transcribe_ext)), ("spec_k_drafts", _c.c_int32), ("n_allowed_languages", _c.c_int32), ("allowed_languages", _c.POINTER(_c.c_char_p))]
transcribe_capabilities._fields_ = [("struct_size", _c.c_uint64), ("native_sample_rate", _c.c_int32), ("n_languages", _c.c_int), ("languages", _c.POINTER(_c.c_char_p)), ("max_timestamp_kind", _c.c_int), ("supports_language_detect", _c.c_bool), ("supports_translate", _c.c_bool), ("supports_streaming", _c.c_bool), ("supports_spec_decode", _c.c_bool), ("max_audio_ms", _c.c_int64), ("n_translate_target_languages", _c.c_int), ("translate_target_languages", _c.POINTER(_c.c_char_p))]
transcribe_session_limits._fields_ = [("struct_size", _c.c_uint64), ("effective_n_ctx", _c.c_int32), ("effective_max_audio_ms", _c.c_int64), ("max_kv_bytes", _c.c_int64)]
transcribe_stream_params._fields_ = [("struct_size", _c.c_uint64), ("family", _c.POINTER(transcribe_ext)), ("commit_policy", _c.c_int), ("stable_prefix_agreement_n", _c.c_uint32)]
Expand Down Expand Up @@ -212,7 +212,7 @@ class transcribe_whisper_chunk_trace(_c.Structure):
'transcribe_device_info': {'size': 64, 'align': 8, 'offsets': {'struct_size': 0, 'name': 8, 'description': 16, 'kind': 24, 'device_id': 32, 'memory_total': 40, 'memory_free': 48, 'device_type': 56}},
'transcribe_model_load_params': {'size': 24, 'align': 8, 'offsets': {'struct_size': 0, 'backend': 8, 'device': 16}},
'transcribe_session_params': {'size': 24, 'align': 8, 'offsets': {'struct_size': 0, 'n_threads': 8, 'kv_type': 12, 'n_ctx': 16}},
'transcribe_run_params': {'size': 72, 'align': 8, 'offsets': {'struct_size': 0, 'task': 8, 'timestamps': 12, 'pnc': 16, 'itn': 20, 'diarize': 24, 'language': 32, 'target_language': 40, 'keep_special_tags': 48, 'family': 56, 'spec_k_drafts': 64}},
'transcribe_run_params': {'size': 80, 'align': 8, 'offsets': {'struct_size': 0, 'task': 8, 'timestamps': 12, 'pnc': 16, 'itn': 20, 'diarize': 24, 'language': 32, 'target_language': 40, 'keep_special_tags': 48, 'family': 56, 'spec_k_drafts': 64, 'n_allowed_languages': 68, 'allowed_languages': 72}},
'transcribe_capabilities': {'size': 56, 'align': 8, 'offsets': {'struct_size': 0, 'native_sample_rate': 8, 'n_languages': 12, 'languages': 16, 'max_timestamp_kind': 24, 'supports_language_detect': 28, 'supports_translate': 29, 'supports_streaming': 30, 'supports_spec_decode': 31, 'max_audio_ms': 32, 'n_translate_target_languages': 40, 'translate_target_languages': 48}},
'transcribe_session_limits': {'size': 32, 'align': 8, 'offsets': {'struct_size': 0, 'effective_n_ctx': 8, 'effective_max_audio_ms': 16, 'max_kv_bytes': 24}},
'transcribe_stream_params': {'size': 24, 'align': 8, 'offsets': {'struct_size': 0, 'family': 8, 'commit_policy': 16, 'stable_prefix_agreement_n': 20}},
Expand Down
12 changes: 9 additions & 3 deletions bindings/rust/sys/src/transcribe_sys.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// @generated by `cargo xtask bindgen` from include/transcribe/extensions.h
// DO NOT EDIT BY HAND. Regenerate: `cargo xtask bindgen`.
// Pinned to include/transcribe.abihash = 7df72bf9e667b8c2
// Pinned to include/transcribe.abihash = 8622da005d6a6fcc

/// The public-ABI digest these bindings were generated against
/// (sha256/16 over the normalized FFI surface). The load-time version
/// gate and the CI drift check both anchor on this value.
pub const PUBLIC_HEADER_HASH: &str = "7df72bf9e667b8c2";
pub const PUBLIC_HEADER_HASH: &str = "8622da005d6a6fcc";

/* automatically generated by rust-bindgen 0.72.1 */

Expand Down Expand Up @@ -346,10 +346,12 @@ pub struct transcribe_run_params {
pub keep_special_tags: bool,
pub family: *const transcribe_ext,
pub spec_k_drafts: i32,
pub n_allowed_languages: i32,
pub allowed_languages: *const *const ::std::os::raw::c_char,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of transcribe_run_params"][::std::mem::size_of::<transcribe_run_params>() - 72usize];
["Size of transcribe_run_params"][::std::mem::size_of::<transcribe_run_params>() - 80usize];
["Alignment of transcribe_run_params"]
[::std::mem::align_of::<transcribe_run_params>() - 8usize];
["Offset of field: transcribe_run_params::struct_size"]
Expand All @@ -374,6 +376,10 @@ const _: () = {
[::std::mem::offset_of!(transcribe_run_params, family) - 56usize];
["Offset of field: transcribe_run_params::spec_k_drafts"]
[::std::mem::offset_of!(transcribe_run_params, spec_k_drafts) - 64usize];
["Offset of field: transcribe_run_params::n_allowed_languages"]
[::std::mem::offset_of!(transcribe_run_params, n_allowed_languages) - 68usize];
["Offset of field: transcribe_run_params::allowed_languages"]
[::std::mem::offset_of!(transcribe_run_params, allowed_languages) - 72usize];
};
unsafe extern "C" {
pub fn transcribe_run_params_init(params: *mut transcribe_run_params);
Expand Down
49 changes: 45 additions & 4 deletions bindings/rust/transcribe-cpp/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub struct RunOptions {
pub diarize: Diarize,
/// Source language hint (ISO code), or `None` to autodetect.
pub language: Option<String>,
/// Limit decoded language tags in automatic mode. Empty is unrestricted.
pub allowed_languages: Vec<String>,
/// Target language for translation, or `None`.
pub target_language: Option<String>,
/// Keep special vocab tags (e.g. `<|...|>`) in the returned text.
Expand All @@ -54,6 +56,7 @@ impl Default for RunOptions {
itn: Itn::Default,
diarize: Diarize::Default,
language: None,
allowed_languages: Vec::new(),
target_language: None,
keep_special_tags: false,
spec_k_drafts: -1,
Expand Down Expand Up @@ -148,7 +151,7 @@ impl Session {
/// On an aborted or truncated decode the partial transcript is preserved
/// on the returned [`Error::Aborted`] / [`Error::OutputTruncated`].
pub fn run(&mut self, pcm: &[f32], options: &RunOptions) -> Result<Transcript> {
let (params, _lang, _target, _family) = build_run_params(options)?;
let (params, _lang, _target, _family, _allowed, _allowed_ptrs) = build_run_params(options)?;
let n = clamp_len(pcm.len())?;

// The compute path is serialized per model; hold the lock for the native
Expand Down Expand Up @@ -191,7 +194,7 @@ impl Session {
pcms: &[&[f32]],
options: &RunOptions,
) -> Result<Vec<Result<Transcript>>> {
let (params, _lang, _target, _family) = build_run_params(options)?;
let (params, _lang, _target, _family, _allowed, _allowed_ptrs) = build_run_params(options)?;
let ptrs: Vec<*const f32> = pcms.iter().map(|p| p.as_ptr()).collect();
let lens: Vec<i32> = pcms
.iter()
Expand Down Expand Up @@ -267,7 +270,7 @@ impl Session {
/// Dropping the returned `Stream` abandons it and returns the session to
/// idle.
pub fn stream(&mut self, run: &RunOptions, stream: &StreamOptions) -> Result<Stream<'_>> {
let (run_params, _lang, _target, _family) = build_run_params(run)?;
let (run_params, _lang, _target, _family, _allowed, _allowed_ptrs) = build_run_params(run)?;
let (stream_params, _stream_family) = build_stream_params(stream);
{
// Claim the model's compute lease for the whole stream lifetime: a
Expand Down Expand Up @@ -423,6 +426,8 @@ type RunParamsBundle = (
Option<CString>,
Option<CString>,
Option<RunExtRaw>,
Vec<CString>,
Vec<*const std::os::raw::c_char>,
);

/// Build `transcribe_run_params` from options. The returned keepalives own the
Expand All @@ -444,6 +449,20 @@ fn build_run_params(o: &RunOptions) -> Result<RunParamsBundle> {
let target = o.target_language.as_deref().map(CString::new).transpose()?;
params.language = lang.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
params.target_language = target.as_ref().map_or(std::ptr::null(), |c| c.as_ptr());
let allowed: Vec<CString> = o
.allowed_languages
.iter()
.map(|code| CString::new(code.as_str()))
.collect::<std::result::Result<_, _>>()?;
let allowed_ptrs: Vec<*const std::os::raw::c_char> =
allowed.iter().map(|code| code.as_ptr()).collect();
params.n_allowed_languages = i32::try_from(allowed_ptrs.len())
.map_err(|_| Error::InvalidArgument("too many allowed languages".into()))?;
params.allowed_languages = if allowed_ptrs.is_empty() {
std::ptr::null()
} else {
allowed_ptrs.as_ptr()
};

let family = o
.family
Expand All @@ -452,7 +471,29 @@ fn build_run_params(o: &RunOptions) -> Result<RunParamsBundle> {
.transpose()?;
params.family = family.as_ref().map_or(std::ptr::null(), |f| f.ext_ptr());

Ok((params, lang, target, family))
Ok((params, lang, target, family, allowed, allowed_ptrs))
}

#[cfg(test)]
mod allowlist_tests {
use super::*;

#[test]
fn run_options_keep_allowed_language_strings_alive() {
let options = RunOptions {
allowed_languages: vec!["en-US".into(), "de-DE".into()],
..Default::default()
};
let (params, _, _, _, codes, pointers) = build_run_params(&options).unwrap();
assert_eq!(params.n_allowed_languages, 2);
assert_eq!(params.allowed_languages, pointers.as_ptr());
assert_eq!(codes[0].to_str().unwrap(), "en-US");
assert_eq!(codes[1].to_str().unwrap(), "de-DE");

let (empty, _, _, _, _, _) = build_run_params(&RunOptions::default()).unwrap();
assert_eq!(empty.n_allowed_languages, 0);
assert!(empty.allowed_languages.is_null());
}
}

/// PCM/utterance lengths cross the ABI as `int`; reject anything that overflows.
Expand Down
6 changes: 3 additions & 3 deletions bindings/typescript/src/_generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// Stable digest of the ABI surface (structs, enums, macros, layout,
// prototypes), computed by the Python oracle and pinned here so a header
// ABI change turns this binding's drift check red for conscious review.
export const PUBLIC_HEADER_HASH = "7df72bf9e667b8c2";
export const PUBLIC_HEADER_HASH = "8622da005d6a6fcc";

// === enum constants ===
export const TRANSCRIBE_OK = 0;
Expand Down Expand Up @@ -121,7 +121,7 @@ export const STRUCT_LAYOUT: Record<string, StructLayout> = {
'transcribe_device_info': { size: 64, align: 8, offsets: {'struct_size': 0, 'name': 8, 'description': 16, 'kind': 24, 'device_id': 32, 'memory_total': 40, 'memory_free': 48, 'device_type': 56} },
'transcribe_model_load_params': { size: 24, align: 8, offsets: {'struct_size': 0, 'backend': 8, 'device': 16} },
'transcribe_session_params': { size: 24, align: 8, offsets: {'struct_size': 0, 'n_threads': 8, 'kv_type': 12, 'n_ctx': 16} },
'transcribe_run_params': { size: 72, align: 8, offsets: {'struct_size': 0, 'task': 8, 'timestamps': 12, 'pnc': 16, 'itn': 20, 'diarize': 24, 'language': 32, 'target_language': 40, 'keep_special_tags': 48, 'family': 56, 'spec_k_drafts': 64} },
'transcribe_run_params': { size: 80, align: 8, offsets: {'struct_size': 0, 'task': 8, 'timestamps': 12, 'pnc': 16, 'itn': 20, 'diarize': 24, 'language': 32, 'target_language': 40, 'keep_special_tags': 48, 'family': 56, 'spec_k_drafts': 64, 'n_allowed_languages': 68, 'allowed_languages': 72} },
'transcribe_capabilities': { size: 56, align: 8, offsets: {'struct_size': 0, 'native_sample_rate': 8, 'n_languages': 12, 'languages': 16, 'max_timestamp_kind': 24, 'supports_language_detect': 28, 'supports_translate': 29, 'supports_streaming': 30, 'supports_spec_decode': 31, 'max_audio_ms': 32, 'n_translate_target_languages': 40, 'translate_target_languages': 48} },
'transcribe_session_limits': { size: 32, align: 8, offsets: {'struct_size': 0, 'effective_n_ctx': 8, 'effective_max_audio_ms': 16, 'max_kv_bytes': 24} },
'transcribe_stream_params': { size: 24, align: 8, offsets: {'struct_size': 0, 'family': 8, 'commit_policy': 16, 'stable_prefix_agreement_n': 20} },
Expand Down Expand Up @@ -166,7 +166,7 @@ export function defineTypes(koffi: any): Record<string, any> {
T['transcribe_device_info'] = koffi.struct({ struct_size: 'uint64_t', name: 'char *', description: 'char *', kind: 'char *', device_id: 'char *', memory_total: 'uint64_t', memory_free: 'uint64_t', device_type: 'int' });
T['transcribe_model_load_params'] = koffi.struct({ struct_size: 'uint64_t', backend: 'int', device: 'void *' });
T['transcribe_session_params'] = koffi.struct({ struct_size: 'uint64_t', n_threads: 'int', kv_type: 'int', n_ctx: 'int32_t' });
T['transcribe_run_params'] = koffi.struct({ struct_size: 'uint64_t', task: 'int', timestamps: 'int', pnc: 'int', itn: 'int', diarize: 'int', language: 'char *', target_language: 'char *', keep_special_tags: 'bool', family: 'void *', spec_k_drafts: 'int32_t' });
T['transcribe_run_params'] = koffi.struct({ struct_size: 'uint64_t', task: 'int', timestamps: 'int', pnc: 'int', itn: 'int', diarize: 'int', language: 'char *', target_language: 'char *', keep_special_tags: 'bool', family: 'void *', spec_k_drafts: 'int32_t', n_allowed_languages: 'int32_t', allowed_languages: 'void *' });
T['transcribe_capabilities'] = koffi.struct({ struct_size: 'uint64_t', native_sample_rate: 'int32_t', n_languages: 'int', languages: 'void *', max_timestamp_kind: 'int', supports_language_detect: 'bool', supports_translate: 'bool', supports_streaming: 'bool', supports_spec_decode: 'bool', max_audio_ms: 'int64_t', n_translate_target_languages: 'int', translate_target_languages: 'void *' });
T['transcribe_session_limits'] = koffi.struct({ struct_size: 'uint64_t', effective_n_ctx: 'int32_t', effective_max_audio_ms: 'int64_t', max_kv_bytes: 'int64_t' });
T['transcribe_stream_params'] = koffi.struct({ struct_size: 'uint64_t', family: 'void *', commit_policy: 'int', stable_prefix_agreement_n: 'uint32_t' });
Expand Down
2 changes: 1 addition & 1 deletion include/transcribe.abihash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7df72bf9e667b8c2
8622da005d6a6fcc
8 changes: 8 additions & 0 deletions include/transcribe.h
Original file line number Diff line number Diff line change
Expand Up @@ -1118,6 +1118,14 @@ struct transcribe_run_params {
* to know whether the field will take effect.
*/
int32_t spec_k_drafts;

/* Optional language allowlist for automatic detection. Codes must match
* model-advertised languages; unknown codes return UNSUPPORTED_LANGUAGE.
* An empty list leaves detection unrestricted. Currently used by
* Nemotron streaming. Ignored when language is explicitly set. The
* library copies strings for the duration of a streaming run. */
int32_t n_allowed_languages;
const char * const * allowed_languages;
};

TRANSCRIBE_API void transcribe_run_params_init(struct transcribe_run_params * params);
Expand Down
Loading