@@ -84,6 +84,44 @@ defmodule Emily.Conformance.WhisperFullTest do
8484 )
8585 end
8686
87+ test "speech_to_text serving lowers fully native — featurizer + decode loop, no fallback" do
88+ repo = { :hf , "openai/whisper-tiny" }
89+ { :ok , whisper } = Bumblebee . load_model ( repo )
90+ { :ok , featurizer } = Bumblebee . load_featurizer ( repo )
91+ { :ok , tokenizer } = Bumblebee . load_tokenizer ( repo )
92+ { :ok , generation_config } = Bumblebee . load_generation_config ( repo )
93+
94+ # The gate is "does the whole graph lower", not transcription quality —
95+ # cap the decode loop so it stays fast.
96+ generation_config = Bumblebee . configure ( generation_config , max_new_tokens: 4 )
97+
98+ # `native_fallback: :raise` makes this a no-fallback gate over the ENTIRE
99+ # serving graph — the mel featurizer's STFT (`fft`), the encoder/decoder
100+ # forward, and the autoregressive decode loop (the multi-output `cond` in
101+ # the encoder attention, `indexed_put` cache writes, dynamic slices). Any
102+ # op the Expr compiler can't lower raises here rather than silently
103+ # degrading. The `mode_test` forward pass above never reaches these: it
104+ # feeds pre-computed mel features through a single `Axon.predict`, so it
105+ # exercises neither the featurizer nor the generation loop.
106+ serving =
107+ Bumblebee.Audio . speech_to_text_whisper ( whisper , featurizer , tokenizer , generation_config ,
108+ defn_options: [ compiler: Emily.Compiler , native: true , native_fallback: :raise ]
109+ )
110+
111+ # ~1 s of deterministic synthetic audio. The featurizer pads it to
112+ # Whisper's 30 s window, so the encoder still runs the full 1500-position
113+ # path (the shape that surfaced the multi-output cond).
114+ audio = Nx . sin ( Nx . iota ( { 16_000 } , type: :f32 ) |> Nx . multiply ( 0.02 ) )
115+
116+ % { chunks: chunks } = Nx.Serving . run ( serving , audio )
117+
118+ # Reaching here is the gate: the full path lowered native with zero
119+ # fallback. The output is only sanity-checked (synthetic audio decodes to
120+ # arbitrary tokens; the transcription itself is not pinned).
121+ assert is_list ( chunks ) and chunks != [ ]
122+ assert Enum . all? ( chunks , & is_binary ( & 1 . text ) )
123+ end
124+
87125 @ tag :fast_kernels_full
88126 test "Whisper-tiny with fused MLX kernels matches the pinned argmax within widened tolerance" do
89127 { :ok , % { model: model , params: params } } =
0 commit comments