1use std::ffi::CString;
15
16use transcribe_cpp_sys as sys;
17
18use crate::error::Result;
19
20#[derive(Debug, Clone, Default, PartialEq)]
24#[cfg_attr(
25 feature = "serde",
26 derive(serde::Serialize, serde::Deserialize),
27 serde(default)
28)]
29pub struct WhisperRunOptions {
30 pub initial_prompt: Option<String>,
31 pub condition_on_prev_tokens: Option<bool>,
32 pub temperature: Option<f32>,
33 pub temperature_inc: Option<f32>,
34 pub compression_ratio_thold: Option<f32>,
35 pub logprob_thold: Option<f32>,
36 pub no_speech_thold: Option<f32>,
37 pub max_prev_context_tokens: Option<i32>,
38 pub seed: Option<u32>,
39 pub max_initial_timestamp: Option<f32>,
40}
41
42#[derive(Debug, Clone, Default, PartialEq, Eq)]
44#[cfg_attr(
45 feature = "serde",
46 derive(serde::Serialize, serde::Deserialize),
47 serde(default)
48)]
49pub struct MoonshineStreamingOptions {
50 pub min_decode_interval_ms: Option<i32>,
51}
52
53#[derive(Debug, Clone, Default, PartialEq, Eq)]
55#[cfg_attr(
56 feature = "serde",
57 derive(serde::Serialize, serde::Deserialize),
58 serde(default)
59)]
60pub struct ParakeetStreamOptions {
61 pub att_context_right: Option<i32>,
62}
63
64#[derive(Debug, Clone, Default, PartialEq, Eq)]
66#[cfg_attr(
67 feature = "serde",
68 derive(serde::Serialize, serde::Deserialize),
69 serde(default)
70)]
71pub struct ParakeetBufferedStreamOptions {
72 pub left_ms: Option<i32>,
73 pub chunk_ms: Option<i32>,
74 pub right_ms: Option<i32>,
75}
76
77#[derive(Debug, Clone, Default, PartialEq, Eq)]
79#[cfg_attr(
80 feature = "serde",
81 derive(serde::Serialize, serde::Deserialize),
82 serde(default)
83)]
84pub struct VoxtralRealtimeStreamOptions {
85 pub num_delay_tokens: Option<i32>,
86 pub min_decode_interval_ms: Option<i32>,
87}
88
89#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94pub enum SortformerPreset {
95 #[default]
96 Default,
97 VeryHighLatency,
99 HighLatency,
101 LowLatency,
104}
105
106impl SortformerPreset {
107 fn to_sys(self) -> sys::transcribe_sortformer_preset {
108 match self {
109 SortformerPreset::Default => {
110 sys::transcribe_sortformer_preset::TRANSCRIBE_SORTFORMER_PRESET_DEFAULT
111 }
112 SortformerPreset::VeryHighLatency => {
113 sys::transcribe_sortformer_preset::TRANSCRIBE_SORTFORMER_PRESET_VERY_HIGH_LATENCY
114 }
115 SortformerPreset::HighLatency => {
116 sys::transcribe_sortformer_preset::TRANSCRIBE_SORTFORMER_PRESET_HIGH_LATENCY
117 }
118 SortformerPreset::LowLatency => {
119 sys::transcribe_sortformer_preset::TRANSCRIBE_SORTFORMER_PRESET_LOW_LATENCY
120 }
121 }
122 }
123}
124
125#[derive(Debug, Clone, Default, PartialEq, Eq)]
129#[cfg_attr(
130 feature = "serde",
131 derive(serde::Serialize, serde::Deserialize),
132 serde(default)
133)]
134pub struct SortformerStreamOptions {
135 pub preset: Option<SortformerPreset>,
136}
137
138#[derive(Debug, Clone, PartialEq)]
140#[non_exhaustive]
141#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
142pub enum RunExtension {
143 Whisper(WhisperRunOptions),
144 Sortformer(SortformerStreamOptions),
145}
146
147#[derive(Debug, Clone, PartialEq, Eq)]
149#[non_exhaustive]
150#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
151pub enum StreamExtension {
152 ParakeetStream(ParakeetStreamOptions),
153 ParakeetBuffered(ParakeetBufferedStreamOptions),
154 MoonshineStreaming(MoonshineStreamingOptions),
155 VoxtralRealtime(VoxtralRealtimeStreamOptions),
156}
157
158pub(crate) enum RunExtRaw {
163 Whisper {
164 ext: Box<sys::transcribe_whisper_run_ext>,
165 _prompt: Option<CString>,
166 },
167 Sortformer(Box<sys::transcribe_sortformer_stream_ext>),
168}
169
170impl RunExtRaw {
171 pub(crate) fn ext_ptr(&self) -> *const sys::transcribe_ext {
172 match self {
173 RunExtRaw::Whisper { ext, .. } => {
175 (&**ext) as *const sys::transcribe_whisper_run_ext as *const sys::transcribe_ext
176 }
177 RunExtRaw::Sortformer(e) => {
178 (&**e) as *const sys::transcribe_sortformer_stream_ext as *const sys::transcribe_ext
179 }
180 }
181 }
182}
183
184impl RunExtension {
185 pub(crate) fn materialize(&self) -> Result<RunExtRaw> {
186 match self {
187 RunExtension::Whisper(o) => {
188 let mut ext: sys::transcribe_whisper_run_ext = unsafe { std::mem::zeroed() };
189 unsafe { sys::transcribe_whisper_run_ext_init(&mut ext) };
190 let prompt = o.initial_prompt.as_deref().map(CString::new).transpose()?;
193 if let Some(c) = prompt.as_ref() {
194 ext.initial_prompt = c.as_ptr();
195 }
196 set(
197 &mut ext.condition_on_prev_tokens,
198 o.condition_on_prev_tokens,
199 );
200 set(&mut ext.temperature, o.temperature);
201 set(&mut ext.temperature_inc, o.temperature_inc);
202 set(&mut ext.compression_ratio_thold, o.compression_ratio_thold);
203 set(&mut ext.logprob_thold, o.logprob_thold);
204 set(&mut ext.no_speech_thold, o.no_speech_thold);
205 set(&mut ext.max_prev_context_tokens, o.max_prev_context_tokens);
206 set(&mut ext.seed, o.seed);
207 set(&mut ext.max_initial_timestamp, o.max_initial_timestamp);
208 Ok(RunExtRaw::Whisper {
209 ext: Box::new(ext),
210 _prompt: prompt,
211 })
212 }
213 RunExtension::Sortformer(o) => {
214 let mut ext: sys::transcribe_sortformer_stream_ext = unsafe { std::mem::zeroed() };
215 unsafe { sys::transcribe_sortformer_stream_ext_init(&mut ext) };
216 set(&mut ext.preset, o.preset.map(SortformerPreset::to_sys));
217 Ok(RunExtRaw::Sortformer(Box::new(ext)))
218 }
219 }
220 }
221}
222
223pub(crate) enum StreamExtRaw {
225 ParakeetStream(Box<sys::transcribe_parakeet_stream_ext>),
226 ParakeetBuffered(Box<sys::transcribe_parakeet_buffered_stream_ext>),
227 MoonshineStreaming(Box<sys::transcribe_moonshine_streaming_stream_ext>),
228 VoxtralRealtime(Box<sys::transcribe_voxtral_realtime_stream_ext>),
229}
230
231impl StreamExtRaw {
232 pub(crate) fn ext_ptr(&self) -> *const sys::transcribe_ext {
233 match self {
234 StreamExtRaw::ParakeetStream(e) => {
235 (&**e) as *const sys::transcribe_parakeet_stream_ext as *const sys::transcribe_ext
236 }
237 StreamExtRaw::ParakeetBuffered(e) => {
238 (&**e) as *const sys::transcribe_parakeet_buffered_stream_ext
239 as *const sys::transcribe_ext
240 }
241 StreamExtRaw::MoonshineStreaming(e) => {
242 (&**e) as *const sys::transcribe_moonshine_streaming_stream_ext
243 as *const sys::transcribe_ext
244 }
245 StreamExtRaw::VoxtralRealtime(e) => {
246 (&**e) as *const sys::transcribe_voxtral_realtime_stream_ext
247 as *const sys::transcribe_ext
248 }
249 }
250 }
251}
252
253impl StreamExtension {
254 pub(crate) fn materialize(&self) -> StreamExtRaw {
255 match self {
256 StreamExtension::ParakeetStream(o) => {
257 let mut e: sys::transcribe_parakeet_stream_ext = unsafe { std::mem::zeroed() };
258 unsafe { sys::transcribe_parakeet_stream_ext_init(&mut e) };
259 set(&mut e.att_context_right, o.att_context_right);
260 StreamExtRaw::ParakeetStream(Box::new(e))
261 }
262 StreamExtension::ParakeetBuffered(o) => {
263 let mut e: sys::transcribe_parakeet_buffered_stream_ext =
264 unsafe { std::mem::zeroed() };
265 unsafe { sys::transcribe_parakeet_buffered_stream_ext_init(&mut e) };
266 set(&mut e.left_ms, o.left_ms);
267 set(&mut e.chunk_ms, o.chunk_ms);
268 set(&mut e.right_ms, o.right_ms);
269 StreamExtRaw::ParakeetBuffered(Box::new(e))
270 }
271 StreamExtension::MoonshineStreaming(o) => {
272 let mut e: sys::transcribe_moonshine_streaming_stream_ext =
273 unsafe { std::mem::zeroed() };
274 unsafe { sys::transcribe_moonshine_streaming_stream_ext_init(&mut e) };
275 set(&mut e.min_decode_interval_ms, o.min_decode_interval_ms);
276 StreamExtRaw::MoonshineStreaming(Box::new(e))
277 }
278 StreamExtension::VoxtralRealtime(o) => {
279 let mut e: sys::transcribe_voxtral_realtime_stream_ext =
280 unsafe { std::mem::zeroed() };
281 unsafe { sys::transcribe_voxtral_realtime_stream_ext_init(&mut e) };
282 set(&mut e.num_delay_tokens, o.num_delay_tokens);
283 set(&mut e.min_decode_interval_ms, o.min_decode_interval_ms);
284 StreamExtRaw::VoxtralRealtime(Box::new(e))
285 }
286 }
287 }
288}
289
290fn set<T>(slot: &mut T, value: Option<T>) {
292 if let Some(v) = value {
293 *slot = v;
294 }
295}