Skip to main content

openai_types/realtime/
manual.rs

1// Manual: hand-crafted realtime types (session builders, enums, transcription).
2
3use serde::{Deserialize, Serialize};
4
5// Re-export shared types (canonical definition in shared/common.rs)
6pub use crate::shared::MaxResponseTokens;
7
8/// Audio format for realtime API.
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
11#[serde(rename_all = "snake_case")]
12#[non_exhaustive]
13pub enum RealtimeAudioFormat {
14    Pcm16,
15    G711Ulaw,
16    G711Alaw,
17}
18
19/// Turn detection type.
20#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
22#[serde(rename_all = "snake_case")]
23#[non_exhaustive]
24pub enum TurnDetectionType {
25    ServerVad,
26    SemanticVad,
27}
28
29/// Eagerness level for semantic VAD.
30#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
31#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
32#[serde(rename_all = "snake_case")]
33#[non_exhaustive]
34pub enum Eagerness {
35    Low,
36    Medium,
37    High,
38    Auto,
39}
40
41/// Noise reduction type for input audio.
42#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43#[cfg_attr(feature = "structured", derive(schemars::JsonSchema))]
44#[serde(rename_all = "snake_case")]
45#[non_exhaustive]
46pub enum NoiseReductionType {
47    NearField,
48    FarField,
49}
50
51// -- Request types --
52
53/// Request body for `POST /realtime/sessions`.
54#[derive(Debug, Clone, Serialize)]
55pub struct SessionCreateRequest {
56    /// The Realtime model to use.
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub model: Option<String>,
59
60    /// The voice the model uses to respond.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub voice: Option<String>,
63
64    /// System instructions for the session.
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub instructions: Option<String>,
67
68    /// The format of input audio.
69    #[serde(skip_serializing_if = "Option::is_none")]
70    pub input_audio_format: Option<RealtimeAudioFormat>,
71
72    /// The format of output audio.
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub output_audio_format: Option<RealtimeAudioFormat>,
75
76    /// Modalities: ["text"], ["audio"], or ["text", "audio"].
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub modalities: Option<Vec<String>>,
79
80    /// Sampling temperature (0.6-1.2).
81    #[serde(skip_serializing_if = "Option::is_none")]
82    pub temperature: Option<f64>,
83
84    /// Maximum output tokens (1-4096 or "inf").
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub max_response_output_tokens: Option<MaxResponseTokens>,
87
88    /// Tools (functions) available to the model.
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub tools: Option<Vec<RealtimeTool>>,
91
92    /// How the model chooses tools.
93    #[serde(skip_serializing_if = "Option::is_none")]
94    pub tool_choice: Option<String>,
95
96    /// Turn detection configuration.
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub turn_detection: Option<TurnDetection>,
99
100    /// Input audio transcription configuration.
101    #[serde(skip_serializing_if = "Option::is_none")]
102    pub input_audio_transcription: Option<InputAudioTranscription>,
103
104    /// Speed of spoken response (0.25-1.5).
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub speed: Option<f64>,
107}
108
109impl SessionCreateRequest {
110    pub fn new() -> Self {
111        Self {
112            model: None,
113            voice: None,
114            instructions: None,
115            input_audio_format: None,
116            output_audio_format: None,
117            modalities: None,
118            temperature: None,
119            max_response_output_tokens: None,
120            tools: None,
121            tool_choice: None,
122            turn_detection: None,
123            input_audio_transcription: None,
124            speed: None,
125        }
126    }
127
128    /// Set the model.
129    pub fn model(mut self, model: impl Into<String>) -> Self {
130        self.model = Some(model.into());
131        self
132    }
133
134    /// Set the voice.
135    pub fn voice(mut self, voice: impl Into<String>) -> Self {
136        self.voice = Some(voice.into());
137        self
138    }
139
140    /// Set instructions.
141    pub fn instructions(mut self, instructions: impl Into<String>) -> Self {
142        self.instructions = Some(instructions.into());
143        self
144    }
145
146    /// Set modalities.
147    pub fn modalities(mut self, modalities: Vec<String>) -> Self {
148        self.modalities = Some(modalities);
149        self
150    }
151}
152
153impl Default for SessionCreateRequest {
154    fn default() -> Self {
155        Self::new()
156    }
157}
158
159/// A function tool for the Realtime API.
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct RealtimeTool {
162    #[serde(rename = "type")]
163    pub type_: String,
164    pub name: String,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub description: Option<String>,
167    #[serde(skip_serializing_if = "Option::is_none")]
168    pub parameters: Option<serde_json::Value>,
169}
170
171/// Turn detection configuration.
172#[derive(Debug, Clone, Serialize, Deserialize)]
173pub struct TurnDetection {
174    /// Turn detection type.
175    #[serde(rename = "type")]
176    pub type_: TurnDetectionType,
177    /// VAD activation threshold (0.0-1.0, server_vad only).
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub threshold: Option<f64>,
180    /// Audio included before speech starts (ms, server_vad only).
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub prefix_padding_ms: Option<i64>,
183    /// Silence duration to detect end (ms, server_vad only).
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub silence_duration_ms: Option<i64>,
186    /// Whether to auto-generate response on VAD stop.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub create_response: Option<bool>,
189    /// Whether to auto-interrupt on VAD start.
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub interrupt_response: Option<bool>,
192    /// Eagerness level for semantic VAD.
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub eagerness: Option<Eagerness>,
195}
196
197/// Input audio transcription configuration.
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct InputAudioTranscription {
200    /// Transcription model (gpt-4o-transcribe, gpt-4o-mini-transcribe, whisper-1).
201    #[serde(skip_serializing_if = "Option::is_none")]
202    pub model: Option<String>,
203    /// Language code (ISO-639-1).
204    #[serde(skip_serializing_if = "Option::is_none")]
205    pub language: Option<String>,
206    /// Optional text to guide the model's style or continue a previous audio segment.
207    #[serde(skip_serializing_if = "Option::is_none")]
208    pub prompt: Option<String>,
209}
210
211/// Input audio noise reduction configuration.
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct InputAudioNoiseReduction {
214    #[serde(rename = "type")]
215    pub type_: NoiseReductionType,
216}
217
218// -- Response types --
219
220/// Ephemeral client secret returned by session creation.
221#[derive(Debug, Clone, Deserialize)]
222pub struct ClientSecret {
223    /// The ephemeral API key value.
224    pub value: String,
225    /// Expiration timestamp.
226    pub expires_at: i64,
227}
228
229/// Response from `POST /realtime/sessions`.
230#[derive(Debug, Clone, Deserialize)]
231pub struct SessionCreateResponse {
232    /// Ephemeral client secret for client-side authentication.
233    pub client_secret: ClientSecret,
234    #[serde(default)]
235    pub model: Option<String>,
236    #[serde(default)]
237    pub voice: Option<String>,
238    #[serde(default)]
239    pub instructions: Option<String>,
240    #[serde(default)]
241    pub modalities: Option<Vec<String>>,
242    #[serde(default)]
243    pub temperature: Option<f64>,
244    #[serde(default)]
245    pub max_response_output_tokens: Option<MaxResponseTokens>,
246    #[serde(default)]
247    pub input_audio_format: Option<RealtimeAudioFormat>,
248    #[serde(default)]
249    pub output_audio_format: Option<RealtimeAudioFormat>,
250    #[serde(default)]
251    pub tools: Option<Vec<RealtimeTool>>,
252    #[serde(default)]
253    pub tool_choice: Option<String>,
254    #[serde(default)]
255    pub turn_detection: Option<TurnDetection>,
256    #[serde(default)]
257    pub speed: Option<f64>,
258}
259
260// -- Client secret config types --
261
262/// Client secret configuration for request (controls token expiration).
263#[derive(Debug, Clone, Serialize)]
264pub struct ClientSecretConfig {
265    /// Expiration configuration.
266    #[serde(skip_serializing_if = "Option::is_none")]
267    pub expires_at: Option<ClientSecretExpiresAt>,
268}
269
270/// Expiration anchor + duration for client secret.
271#[derive(Debug, Clone, Serialize)]
272pub struct ClientSecretExpiresAt {
273    /// Anchor point -- only "created_at" is currently supported.
274    pub anchor: String,
275    /// Seconds from anchor to expiration (10-7200).
276    pub seconds: i64,
277}
278
279// -- Transcription session types --
280
281/// Request body for `POST /realtime/transcription_sessions`.
282///
283/// Creates a transcription-only Realtime session with an ephemeral token.
284/// Unlike `/realtime/sessions`, this endpoint is specialized for STT
285/// (no voice output, no response generation).
286#[derive(Debug, Clone, Serialize)]
287pub struct TranscriptionSessionCreateRequest {
288    /// Configuration for the ephemeral token expiration.
289    #[serde(skip_serializing_if = "Option::is_none")]
290    pub client_secret: Option<ClientSecretConfig>,
291
292    /// Items to include in transcription (e.g. "item.input_audio_transcription.logprobs").
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub include: Option<Vec<String>>,
295
296    /// The format of input audio (pcm16, g711_ulaw, g711_alaw).
297    #[serde(skip_serializing_if = "Option::is_none")]
298    pub input_audio_format: Option<RealtimeAudioFormat>,
299
300    /// Configuration for input audio noise reduction.
301    #[serde(skip_serializing_if = "Option::is_none")]
302    pub input_audio_noise_reduction: Option<InputAudioNoiseReduction>,
303
304    /// Configuration for input audio transcription (model + language + prompt).
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub input_audio_transcription: Option<InputAudioTranscription>,
307
308    /// Modalities: ["text"] or ["text", "audio"].
309    #[serde(skip_serializing_if = "Option::is_none")]
310    pub modalities: Option<Vec<String>>,
311
312    /// Turn detection configuration (server_vad or semantic_vad).
313    #[serde(skip_serializing_if = "Option::is_none")]
314    pub turn_detection: Option<TurnDetection>,
315}
316
317impl TranscriptionSessionCreateRequest {
318    pub fn new() -> Self {
319        Self {
320            client_secret: None,
321            include: None,
322            input_audio_format: None,
323            input_audio_noise_reduction: None,
324            input_audio_transcription: None,
325            modalities: None,
326            turn_detection: None,
327        }
328    }
329
330    pub fn input_audio_format(mut self, format: RealtimeAudioFormat) -> Self {
331        self.input_audio_format = Some(format);
332        self
333    }
334
335    pub fn transcription(mut self, model: impl Into<String>, language: impl Into<String>) -> Self {
336        self.input_audio_transcription = Some(InputAudioTranscription {
337            model: Some(model.into()),
338            language: Some(language.into()),
339            prompt: None,
340        });
341        self
342    }
343
344    pub fn turn_detection(mut self, td: TurnDetection) -> Self {
345        self.turn_detection = Some(td);
346        self
347    }
348
349    pub fn noise_reduction(mut self, type_: NoiseReductionType) -> Self {
350        self.input_audio_noise_reduction = Some(InputAudioNoiseReduction { type_ });
351        self
352    }
353
354    pub fn include(mut self, items: Vec<String>) -> Self {
355        self.include = Some(items);
356        self
357    }
358
359    pub fn modalities(mut self, modalities: Vec<String>) -> Self {
360        self.modalities = Some(modalities);
361        self
362    }
363
364    pub fn expires_in(mut self, seconds: i64) -> Self {
365        self.client_secret = Some(ClientSecretConfig {
366            expires_at: Some(ClientSecretExpiresAt {
367                anchor: "created_at".into(),
368                seconds,
369            }),
370        });
371        self
372    }
373}
374
375impl Default for TranscriptionSessionCreateRequest {
376    fn default() -> Self {
377        Self::new()
378    }
379}
380
381/// Response from `POST /realtime/transcription_sessions`.
382///
383/// Simpler than `SessionCreateResponse` -- no model/voice/tools/instructions.
384#[derive(Debug, Clone, Deserialize)]
385pub struct TranscriptionSession {
386    /// Ephemeral client secret for client-side authentication.
387    pub client_secret: ClientSecret,
388    /// The format of input audio.
389    #[serde(default)]
390    pub input_audio_format: Option<String>,
391    /// Transcription configuration.
392    #[serde(default)]
393    pub input_audio_transcription: Option<InputAudioTranscription>,
394    /// Modalities.
395    #[serde(default)]
396    pub modalities: Option<Vec<String>>,
397    /// Turn detection configuration.
398    #[serde(default)]
399    pub turn_detection: Option<TurnDetection>,
400}