Skip to content

feat(asr): raw encoder-outputs callback for streaming ASR managers - #1109

Open
donpark wants to merge 1 commit into
FluidInference:mainfrom
donpark:encoder-output-callback
Open

donpark wants to merge 1 commit into
FluidInference:mainfrom
donpark:encoder-output-callback

Conversation

@donpark

@donpark donpark commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

What

An opt-in raw encoder-outputs callback for the streaming ASR managers (StreamingUnifiedAsrManager and StreamingNemotronAsrManager):

manager.setEncoderOutputCallback { outputs, localFrames, globalOrigin in
    // outputs: every encoder prediction output by name (incl. extra tap_* outputs
    //          a re-exported encoder declares)
    // localFrames: the frame range this step decodes (within the prediction)
    // globalOrigin: global encoder-frame index of local frame 0  (global = origin + local)
}

Default behavior is unchanged — the hook is nil unless set.

Why

On-device turn-decision models (end-of-utterance, barge-in, backchannel timing) read encoder-layer taps per frame alongside transcription. Without access to the encoder outputs, apps must run a second encoder chain just to extract features — in our app that is a ~390 MB duplicate model and a redundant encoder pass per frame.

This hook lets one encoder pass serve both the RNNT decoder and feature consumers. Combined with an encoder export that declares extra outputs (e.g. an intermediate tap_l12), it enables sharing the ASR's own encoder for downstream features with zero duplicated compute.

Details

  • Identical hook contract on both managers: ([String: MLMultiArray], Range<Int>, Int) -> Void.
  • StreamingNemotronAsrManager tracks tapFrameOrigin across chunks and resets it with the caches in resetStates().
  • The unified manager (stateless window re-encode) passes plan.bufferStartFrame as the origin.
  • No behavior change when the hook is unset; no API removals.

Happy to adjust naming/shape (e.g. a delegate protocol instead of a closure) to match project conventions.

Add an opt-in hook to the streaming ASR managers (StreamingUnifiedAsrManager,
StreamingNemotronAsrManager): `setEncoderOutputCallback` receives each encoder
prediction's raw outputs plus the step's local frame range and global frame
origin (global = origin + local), so consumers can read intermediate features —
e.g. layer taps from an encoder re-exported with extra declared outputs —
without a second encoder pass.

Motivation: on-device turn-decision models read encoder-layer taps per frame.
Today that means running a second encoder chain beside the ASR (a ~390 MB
duplicate in our app); this hook lets one pass serve both transcription and
feature consumers. Unset (default) behavior is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant