1use crate::audio::AudioEncoding;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use std::ops::{Deref, DerefMut};
7
8#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum InterruptionDetection {
23 #[default]
29 Manual,
30 Automatic,
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
41#[serde(rename_all = "snake_case")]
42pub enum VadMode {
43 #[default]
45 ServerVad,
46 SemanticVad,
48 None,
59}
60
61#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
63pub struct VadConfig {
64 #[serde(rename = "type")]
66 pub mode: VadMode,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub silence_duration_ms: Option<u32>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub threshold: Option<f32>,
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub prefix_padding_ms: Option<u32>,
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub interrupt_response: Option<bool>,
79 #[serde(skip_serializing_if = "Option::is_none")]
81 pub eagerness: Option<String>,
82}
83
84impl Default for VadConfig {
85 fn default() -> Self {
86 Self {
87 mode: VadMode::ServerVad,
88 silence_duration_ms: Some(500),
89 threshold: None,
90 prefix_padding_ms: None,
91 interrupt_response: Some(true),
92 eagerness: None,
93 }
94 }
95}
96
97impl VadConfig {
98 pub fn server_vad() -> Self {
100 Self::default()
101 }
102
103 pub fn semantic_vad() -> Self {
105 Self { mode: VadMode::SemanticVad, ..Default::default() }
106 }
107
108 pub fn disabled() -> Self {
110 Self { mode: VadMode::None, ..Default::default() }
111 }
112
113 pub fn with_silence_duration(mut self, ms: u32) -> Self {
115 self.silence_duration_ms = Some(ms);
116 self
117 }
118
119 pub fn with_interrupt(mut self, interrupt: bool) -> Self {
121 self.interrupt_response = Some(interrupt);
122 self
123 }
124}
125
126#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
128pub struct ToolDefinition {
129 pub name: String,
131 #[serde(skip_serializing_if = "Option::is_none")]
133 pub description: Option<String>,
134 #[serde(skip_serializing_if = "Option::is_none")]
136 pub parameters: Option<Value>,
137}
138
139impl ToolDefinition {
140 pub fn new(name: impl Into<String>) -> Self {
142 Self { name: name.into(), description: None, parameters: None }
143 }
144
145 pub fn with_description(mut self, desc: impl Into<String>) -> Self {
147 self.description = Some(desc.into());
148 self
149 }
150
151 pub fn with_parameters(mut self, schema: Value) -> Self {
153 self.parameters = Some(schema);
154 self
155 }
156}
157
158#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
160pub struct RealtimeConfig {
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub model: Option<String>,
164
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub instruction: Option<String>,
168
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub voice: Option<String>,
172
173 #[serde(skip_serializing_if = "Option::is_none")]
175 pub modalities: Option<Vec<String>>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub input_audio_format: Option<AudioEncoding>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub output_audio_format: Option<AudioEncoding>,
184
185 #[serde(skip_serializing_if = "Option::is_none")]
187 pub turn_detection: Option<VadConfig>,
188
189 #[serde(skip_serializing_if = "Option::is_none")]
191 pub tools: Option<Vec<ToolDefinition>>,
192
193 #[serde(skip_serializing_if = "Option::is_none")]
195 pub tool_choice: Option<String>,
196
197 #[serde(skip_serializing_if = "Option::is_none")]
199 pub input_audio_transcription: Option<TranscriptionConfig>,
200
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub temperature: Option<f32>,
204
205 #[serde(skip_serializing_if = "Option::is_none")]
207 pub max_response_output_tokens: Option<u32>,
208
209 #[serde(skip_serializing_if = "Option::is_none")]
211 pub cached_content: Option<String>,
212
213 #[serde(skip_serializing_if = "Option::is_none")]
219 pub interruption_detection: Option<InterruptionDetection>,
220
221 #[serde(skip_serializing_if = "Option::is_none")]
225 pub affective_dialog: Option<bool>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub extra: Option<Value>,
230}
231
232#[derive(Debug, Clone, Default, Serialize, Deserialize)]
257#[serde(transparent)]
258pub struct SessionUpdateConfig(pub RealtimeConfig);
259
260impl Deref for SessionUpdateConfig {
261 type Target = RealtimeConfig;
262
263 fn deref(&self) -> &Self::Target {
264 &self.0
265 }
266}
267
268impl DerefMut for SessionUpdateConfig {
269 fn deref_mut(&mut self) -> &mut Self::Target {
270 &mut self.0
271 }
272}
273
274impl From<RealtimeConfig> for SessionUpdateConfig {
275 fn from(config: RealtimeConfig) -> Self {
276 Self(config)
277 }
278}
279
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
282pub struct TranscriptionConfig {
283 pub model: String,
285}
286
287impl TranscriptionConfig {
288 pub fn whisper() -> Self {
290 Self { model: "whisper-1".to_string() }
291 }
292}
293
294impl RealtimeConfig {
295 pub fn new() -> Self {
297 Self::default()
298 }
299
300 pub fn builder() -> RealtimeConfigBuilder {
302 RealtimeConfigBuilder::new()
303 }
304
305 pub fn with_model(mut self, model: impl Into<String>) -> Self {
307 self.model = Some(model.into());
308 self
309 }
310
311 pub fn with_instruction(mut self, instruction: impl Into<String>) -> Self {
313 self.instruction = Some(instruction.into());
314 self
315 }
316
317 pub fn with_voice(mut self, voice: impl Into<String>) -> Self {
319 self.voice = Some(voice.into());
320 self
321 }
322
323 pub fn with_modalities(mut self, modalities: Vec<String>) -> Self {
325 self.modalities = Some(modalities);
326 self
327 }
328
329 pub fn with_text_and_audio(mut self) -> Self {
331 self.modalities = Some(vec!["text".to_string(), "audio".to_string()]);
332 self
333 }
334
335 pub fn with_audio_only(mut self) -> Self {
337 self.modalities = Some(vec!["audio".to_string()]);
338 self
339 }
340
341 pub fn with_vad(mut self, vad: VadConfig) -> Self {
343 self.turn_detection = Some(vad);
344 self
345 }
346
347 pub fn with_server_vad(self) -> Self {
349 self.with_vad(VadConfig::server_vad())
350 }
351
352 pub fn without_vad(mut self) -> Self {
358 self.turn_detection = Some(VadConfig::disabled());
359 self
360 }
361
362 pub fn with_tool(mut self, tool: ToolDefinition) -> Self {
364 self.tools.get_or_insert_with(Vec::new).push(tool);
365 self
366 }
367
368 pub fn with_tools(mut self, tools: Vec<ToolDefinition>) -> Self {
370 self.tools = Some(tools);
371 self
372 }
373
374 pub fn with_transcription(mut self) -> Self {
376 self.input_audio_transcription = Some(TranscriptionConfig::whisper());
377 self
378 }
379
380 pub fn with_temperature(mut self, temp: f32) -> Self {
382 self.temperature = Some(temp);
383 self
384 }
385
386 pub fn with_affective_dialog(mut self, enabled: bool) -> Self {
389 self.affective_dialog = Some(enabled);
390 self
391 }
392
393 pub fn with_cached_content(mut self, content: impl Into<String>) -> Self {
395 self.cached_content = Some(content.into());
396 self
397 }
398
399 pub fn with_interruption_detection(mut self, mode: InterruptionDetection) -> Self {
403 self.interruption_detection = Some(mode);
404 self
405 }
406
407 pub fn with_automatic_interruption(self) -> Self {
412 self.with_interruption_detection(InterruptionDetection::Automatic)
413 }
414}
415
416#[derive(Debug, Clone, Default)]
418pub struct RealtimeConfigBuilder {
419 config: RealtimeConfig,
420}
421
422impl RealtimeConfigBuilder {
423 pub fn new() -> Self {
425 Self::default()
426 }
427
428 pub fn model(mut self, model: impl Into<String>) -> Self {
430 self.config.model = Some(model.into());
431 self
432 }
433
434 pub fn instruction(mut self, instruction: impl Into<String>) -> Self {
436 self.config.instruction = Some(instruction.into());
437 self
438 }
439
440 pub fn voice(mut self, voice: impl Into<String>) -> Self {
442 self.config.voice = Some(voice.into());
443 self
444 }
445
446 pub fn vad_enabled(mut self, enabled: bool) -> Self {
448 if enabled {
449 self.config.turn_detection = Some(VadConfig::server_vad());
450 } else {
451 self.config.turn_detection = Some(VadConfig::disabled());
452 }
453 self
454 }
455
456 pub fn vad(mut self, vad: VadConfig) -> Self {
458 self.config.turn_detection = Some(vad);
459 self
460 }
461
462 pub fn tool(mut self, tool: ToolDefinition) -> Self {
464 self.config.tools.get_or_insert_with(Vec::new).push(tool);
465 self
466 }
467
468 pub fn temperature(mut self, temp: f32) -> Self {
470 self.config.temperature = Some(temp);
471 self
472 }
473
474 pub fn cached_content(mut self, content: impl Into<String>) -> Self {
476 self.config.cached_content = Some(content.into());
477 self
478 }
479
480 pub fn interruption_detection(mut self, mode: InterruptionDetection) -> Self {
482 self.config.interruption_detection = Some(mode);
483 self
484 }
485
486 pub fn build(self) -> RealtimeConfig {
488 self.config
489 }
490}