#ifndef PARAKEET_CAPI_H #define PARAKEET_CAPI_H #ifdef __cplusplus extern "C" { #endif // Flat C-API for parakeet.cpp — designed for dlopen / cgo / purego (LocalAI). // // All functions are extern "C" and never let a C++ exception cross the // boundary. The model is loaded ONCE into an opaque `parakeet_ctx` and reused // across transcribe calls. Returned strings are malloc'd UTF-8 owned by the // caller and must be released with parakeet_capi_free_string. // Opaque transcription context (wraps a loaded model + last-error buffer). typedef struct parakeet_ctx parakeet_ctx; // ABI version of this header/implementation. Bump on any breaking change to the // function signatures or semantics below. // // v3: added the target_lang variants (parakeet_capi_transcribe_path_lang, // parakeet_capi_transcribe_pcm_lang, parakeet_capi_stream_begin_lang, // parakeet_capi_transcribe_pcm_batch_json_lang, // parakeet_capi_transcribe_pcm_batch_lang) for multilingual // prompt-conditioned (nemotron) models. The original non-lang entry points // are unchanged and delegate with the model default language. // // v4: added the streaming JSON entry points (parakeet_capi_stream_feed_json, // parakeet_capi_stream_finalize_json) that surface per-word timestamps // (start/end/conf) plus frame_sec alongside the newly-finalized text, and // added "frame_sec" to the transcribe_*_json documents. The original entry // points are unchanged. // // v5: the (end of utterance) vs (end of backchannel) distinction is // now visible across the C boundary. BREAKING semantics on the streaming // surface: parakeet_capi_stream_feed's `*eou_out` is now a bitmask // (PARAKEET_EVENT_EOU | PARAKEET_EVENT_EOB) instead of an any-event 0/1, // and the JSON "eou" field now means "an fired" only, with a new // "eob" field beside it (in v4 both meant "an OR fired"). // Added parakeet_capi_stream_drain_events (typed per-event records with // is_eob + timestamps, freed with parakeet_capi_free_events) and an // "events" array in the stream_feed_json / stream_finalize_json documents. int parakeet_capi_abi_version(void); // Load a GGUF model. Returns an owning context, or NULL on failure. // The returned context must be released with parakeet_capi_free. parakeet_ctx* parakeet_capi_load(const char* gguf_path); // Firefox-local: load a GGUF model from an already-open file descriptor (for // sandboxed hosts that cannot open paths). The fd remains owned by the caller. // Returns an owning context, or NULL on failure. parakeet_ctx* parakeet_capi_load_fd(int fd); // Free a context obtained from parakeet_capi_load. Safe on NULL. void parakeet_capi_free(parakeet_ctx* ctx); // Transcribe a WAV file. `decoder` selects the head: // 0 = default (by arch: transducer for tdt/rnnt/hybrid, CTC for ctc), // 1 = ctc (force CTC head), // 2 = tdt/rnnt (force the transducer head). // On success returns a malloc'd, NUL-terminated UTF-8 transcript (free with // parakeet_capi_free_string). On error returns NULL and sets the context's // last error (see parakeet_capi_last_error). char* parakeet_capi_transcribe_path(parakeet_ctx* ctx, const char* wav_path, int decoder); // Transcribe in-memory mono float PCM (`samples`, length `n_samples`). If // `sample_rate != 16000` the audio is linearly resampled to 16 kHz first. // `decoder` is as in parakeet_capi_transcribe_path. On success returns a // malloc'd UTF-8 transcript (free with parakeet_capi_free_string); on error // returns NULL and sets the context's last error. char* parakeet_capi_transcribe_pcm(parakeet_ctx* ctx, const float* samples, int n_samples, int sample_rate, int decoder); // Like parakeet_capi_transcribe_path but selects the language prompt for // multilingual (nemotron) models. `target_lang` is a locale string (e.g. "en", // "de", "auto"); NULL or "" uses the model's default ("auto"). Ignored by // non-prompt models. On an unknown locale (for a prompt model) returns NULL and // sets the context's last error. parakeet_capi_transcribe_path delegates here // with the model default. char* parakeet_capi_transcribe_path_lang(parakeet_ctx* ctx, const char* wav_path, int decoder, const char* target_lang); // Like parakeet_capi_transcribe_pcm but selects the language prompt (see // parakeet_capi_transcribe_path_lang for `target_lang` semantics). char* parakeet_capi_transcribe_pcm_lang(parakeet_ctx* ctx, const float* samples, int n_samples, int sample_rate, int decoder, const char* target_lang); // Transcribe a batch of in-memory mono float PCM clips. `samples` is an array of // `n_clips` pointers and `n_samples` an array of `n_clips` per-clip lengths; each // clip is resampled to 16 kHz if `sample_rate != 16000`. `decoder` is as in // parakeet_capi_transcribe_path (0=default,1=ctc,2=tdt/rnnt). On success returns // 0 and fills `out` (a caller-allocated array of `n_clips` char*) with malloc'd // NUL-terminated UTF-8 transcripts; release each with parakeet_capi_free_string. // On error returns nonzero, sets the context's last error (see // parakeet_capi_last_error), and leaves every out[] entry NULL: the caller owns // nothing and has nothing to free. int parakeet_capi_transcribe_pcm_batch(parakeet_ctx* ctx, const float* const* samples, const int* n_samples, int n_clips, int sample_rate, int decoder, char** out); // Like parakeet_capi_transcribe_pcm_batch but selects the language prompt for // multilingual (nemotron) models. ONE `target_lang` applies to the whole batch: // a locale string (e.g. "en", "de", "auto"); NULL or "" uses the model's // default ("auto"). Ignored by non-prompt models. On an unknown locale (for a // prompt model) returns nonzero, sets the context's last error, and leaves // every out[] entry NULL. parakeet_capi_transcribe_pcm_batch delegates here // with the model default. int parakeet_capi_transcribe_pcm_batch_lang(parakeet_ctx* ctx, const float* const* samples, const int* n_samples, int n_clips, int sample_rate, int decoder, const char* target_lang, char** out); // Transcribe a WAV file returning a malloc'd UTF-8 JSON document with per-word // and per-token timestamps + confidence (matching NeMo timestamps=True and the // 'max_prob' confidence method). `decoder` is as in // parakeet_capi_transcribe_path. The JSON shape is: // // {"text":"...", // "frame_sec":0.080000, // "words":[{"w":"...","start":0.480,"end":0.640,"conf":0.9100}, ...], // "tokens":[{"id":123,"t":0.480,"conf":0.9100}, ...]} // // where "start"/"end"/"t" are seconds (3 decimals) and "conf" is the // confidence in (0,1] (4 decimals). "frame_sec" is the encoder frame stride in // seconds (hop_length * subsampling_factor / sample_rate); multiply a frame-unit // segment gap threshold by it to get the seconds gap between words. The // "w"/"text" strings are JSON-escaped // (", \\, and control chars). On success returns the malloc'd string (free with // parakeet_capi_free_string); on error returns NULL and sets the context's last // error. char* parakeet_capi_transcribe_path_json(parakeet_ctx* ctx, const char* wav_path, int decoder); // Batched transcription with timestamps, returning ONE malloc'd JSON string that // is a JSON ARRAY of n_clips objects, each identical in shape to // parakeet_capi_transcribe_path_json's document ({"text","words","tokens"}). // samples_concat holds all clips' 16 kHz mono float samples concatenated; // n_samples gives each clip's sample count; n_clips is the array length. // decoder: 0=default,1=ctc,2=tdt. PRECONDITION (caller MUST uphold, not // validated here): the sum of n_samples[0..n_clips) equals the number of floats // in samples_concat. A larger sum reads out of bounds. // Returns the JSON string on success (free with parakeet_capi_free_string), or // NULL on error (see parakeet_capi_last_error). char* parakeet_capi_transcribe_pcm_batch_json(parakeet_ctx* ctx, const float* samples_concat, const int* n_samples, int n_clips, int sample_rate, int decoder); // Like parakeet_capi_transcribe_pcm_batch_json but selects the language prompt // for multilingual (nemotron) models. ONE `target_lang` applies to the whole // batch: a locale string (e.g. "en", "de", "auto"); NULL or "" uses the model's // default ("auto"). Ignored by non-prompt models. On an unknown locale (for a // prompt model) returns NULL and sets the context's last error. // parakeet_capi_transcribe_pcm_batch_json delegates here with the model default. char* parakeet_capi_transcribe_pcm_batch_json_lang(parakeet_ctx* ctx, const float* samples_concat, const int* n_samples, int n_clips, int sample_rate, int decoder, const char* target_lang); // --------------------------------------------------------------------------- // Streaming API (cache-aware streaming RNN-T, e.g. the EOU model // nvidia/parakeet_realtime_eou_120m-v1). The stream session buffers incoming // 16 kHz mono float PCM, runs the mel front end + cache-aware StreamingEncoder + // carried RNN-T decoder, and surfaces newly-finalized text plus end-of-utterance // () / backchannel () events. No C++ exception crosses the boundary. // --------------------------------------------------------------------------- // Opaque streaming session. Begun from a loaded context; the context (and its // model) must outlive the stream. Free with parakeet_capi_stream_free. typedef struct parakeet_stream parakeet_stream; // Begin a streaming session over `ctx`'s model. Returns NULL on failure (e.g. // the model is not a cache-aware streaming model) and sets the ctx last error. parakeet_stream* parakeet_capi_stream_begin(parakeet_ctx* ctx); // Begin a streaming session selecting the language prompt for multilingual // (nemotron) prompt-conditioned models. `target_lang` is a locale string (e.g. // "en", "de", "auto"); NULL or "" uses the model's default. Ignored by // non-prompt models. Returns NULL on failure (not a streaming model, or an // unknown locale) and sets the ctx last error. parakeet_capi_stream_begin // delegates here with the model default. parakeet_stream* parakeet_capi_stream_begin_lang(parakeet_ctx* ctx, const char* target_lang); // Bits for parakeet_capi_stream_feed's *eou_out mask. = the user // finished a complete utterance (a voice agent responds); = the user // finished a backchannel, a short acknowledgment like "uh-huh" while the other // party speaks (a voice agent must NOT treat it as the user taking the turn). #define PARAKEET_EVENT_EOU 1 #define PARAKEET_EVENT_EOB 2 // Feed a block of 16 kHz MONO float PCM (`pcm`, length `n_samples`). The session // buffers the audio and decodes as full encoder chunks become available. // Returns the newly-finalized text since the last call as a malloc'd UTF-8 // string (free with parakeet_capi_free_string) — "" (empty, non-NULL) if no new // text was finalized this call, NULL only on error. / are stripped // from the text and surfaced as events: if `eou_out` is non-NULL it is set to // the bitwise OR of PARAKEET_EVENT_EOU / PARAKEET_EVENT_EOB for the event types // that fired during this feed (0 if none). Per-event timestamps are available // via parakeet_capi_stream_drain_events. char* parakeet_capi_stream_feed(parakeet_stream* s, const float* pcm, int n_samples, int* eou_out); // Flush the end-of-stream tail: process any remaining buffered audio (the final // chunk completes the streaming tail). Returns the final newly-finalized text // (malloc'd; "" if none, NULL on error). After this the running transcript is // complete. Does NOT fabricate an NeMo's streaming would not emit. char* parakeet_capi_stream_finalize(parakeet_stream* s); // One / event emitted by the streaming decoder. marks the end // of a complete utterance (the user yielded the turn); marks the end of a // backchannel (a short acknowledgment like "uh-huh" while the other party // speaks — a voice agent typically responds on but must NOT treat // as the user taking the turn). time_sec is the absolute (stream-relative) // emission time: encoder_frame * frame_sec. typedef struct parakeet_stream_event { int token; // raw vocab id of the special token int is_eob; // 0 = (end of utterance), 1 = (backchannel) int encoder_frame; // absolute encoder-output frame index of the emission float time_sec; // encoder_frame * frame_sec, seconds from stream start } parakeet_stream_event; // Drain the / events accumulated since the last drain. On success // returns the event count (>= 0) and, when the count is nonzero, sets // `*out_events` to a malloc'd array of that many records (release with // parakeet_capi_free_events); `*out_events` is NULL when the count is 0. // Returns -1 on error (NULL stream/out pointer) with `*out_events` NULL. // The queue is shared with the JSON entry points: stream_feed_json / // stream_finalize_json also drain it (into their "events" array), so use one // style or the other per stream. int parakeet_capi_stream_drain_events(parakeet_stream* s, parakeet_stream_event** out_events); // Free an event array previously returned by parakeet_capi_stream_drain_events. // Safe on NULL. void parakeet_capi_free_events(parakeet_stream_event* events); // Firefox-local: a finalized word with timing + confidence. Same data the JSON // "words" array carries, in a typed form so the host need not parse JSON. typedef struct parakeet_stream_word { const char* text; // malloc'd UTF-8; freed by parakeet_capi_free_words float start; // seconds from stream start float end; float conf; // 0..1 } parakeet_stream_word; // Drain the words finalized since the previous call (the same set whose text // stream_feed returned). Returns the count (>= 0), or -1 on error; on success // *out_words is a malloc'd array of `count` entries (free with // parakeet_capi_free_words). Mutually exclusive with the JSON feed entry points. int parakeet_capi_stream_drain_words(parakeet_stream* s, parakeet_stream_word** out_words); // Free a word array (and each word's text) from parakeet_capi_stream_drain_words. // Safe on NULL. void parakeet_capi_free_words(parakeet_stream_word* words, int count); // Like parakeet_capi_stream_feed but returns a malloc'd UTF-8 JSON document // instead of bare text: // {"text":"...","eou":0,"eob":0,"frame_sec":0.080000, // "events":[{"type":"eou","frame":31,"t":2.480}, ...], // "words":[{"w":"...","start":0.480,"end":0.640,"conf":0.9100}, ...]} // "text" is the newly-finalized text since the last call ("" if none); "eou" is // 1 iff an fired during this feed and "eob" 1 iff an fired (see // parakeet_stream_event for the semantics — they are distinct turn-taking // signals, not conflated); "frame_sec" is the encoder frame stride in seconds; // "events" are the / events drained this call, each with "type" // ("eou" = end of utterance, "eob" = backchannel), the absolute encoder frame // and the emission time in seconds (frame * frame_sec); "words" are the words // finalized this call with absolute (stream-relative) start/end seconds and // 'min'-aggregate confidence (the same drain as the offline pk::group_words). // Returns NULL only on error (see parakeet_capi_last_error). Free with // parakeet_capi_free_string. char* parakeet_capi_stream_feed_json(parakeet_stream* s, const float* pcm, int n_samples); // Like parakeet_capi_stream_finalize but returns the same JSON document shape as // parakeet_capi_stream_feed_json (flushing the end-of-stream tail; "eou" is // typically 0 — finalize does not fabricate an ). Free with // parakeet_capi_free_string; NULL only on error. char* parakeet_capi_stream_finalize_json(parakeet_stream* s); // Free a streaming session. Safe on NULL. void parakeet_capi_stream_free(parakeet_stream* s); // Free a string previously returned by parakeet_capi_transcribe_* / // parakeet_capi_stream_*. Safe on NULL. void parakeet_capi_free_string(char* s); // Human-readable description of the last error on `ctx`, or "" if none. // The returned pointer is owned by the context and valid until the next call on // it (or until parakeet_capi_free). Returns "" if `ctx` is NULL. const char* parakeet_capi_last_error(parakeet_ctx* ctx); #ifdef __cplusplus } // extern "C" #endif #endif // PARAKEET_CAPI_H