openai_interface/realtime/mod.rs
1//! The Realtime API (HTTP part): create ephemeral client sessions via
2//! `/realtime`.
3//!
4//! > ![warn] This module is untested!
5//! > If you encounter any issues, please report them on the repository.
6//!
7//! The Realtime API's primary transport is WebSocket, which this crate
8//! does not implement. The two HTTP endpoints here create the
9//! short-lived session tokens a browser or mobile client uses to open
10//! that WebSocket connection, so they can be issued from a backend
11//! without exposing the API key. See
12//! [the OpenAI Realtime guide](https://platform.openai.com/docs/guides/realtime).
13//!
14//! The session configuration (modalities, voice, tools, turn
15//! detection, ...) is passed through as raw JSON, because it changes
16//! frequently and only matters to the WebSocket client consuming it.
17
18pub mod transcription_sessions;
19
20use serde::Serialize;
21use url::Url;
22
23use crate::{
24 errors::OapiError,
25 rest::post::{Post, PostNoStream},
26};
27
28/// Creates a Realtime session via `POST /realtime/sessions`.
29///
30/// The `session` field carries the full session configuration as raw
31/// JSON (modalities, model, voice, instructions, tools,
32/// turn_detection, ...), matching the official API's nested shape.
33#[derive(Debug, Clone, Serialize)]
34pub struct CreateRealtimeSessionRequest {
35 /// The session configuration, as raw JSON. Use `{"model": ...}` at
36 /// minimum; all other fields are optional server-side.
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub session: Option<serde_json::Value>,
39 /// Additional JSON properties flattened into the request body, for
40 /// fields not covered by the typed struct.
41 #[serde(flatten, skip_serializing_if = "Option::is_none")]
42 pub extra_body: Option<serde_json::Map<String, serde_json::Value>>,
43}
44
45/// A client secret of a Realtime session.
46#[derive(Debug, Clone, serde::Deserialize)]
47pub struct RealtimeClientSecret {
48 /// The secret token itself, e.g. `ek_...`.
49 pub value: String,
50 /// Unix timestamp (seconds) of when the secret expires.
51 #[serde(default)]
52 pub expires_at: Option<u64>,
53}
54
55/// The response of a Realtime session creation.
56#[derive(Debug, Clone, serde::Deserialize)]
57pub struct RealtimeSession {
58 /// The object type (`realtime.session`).
59 #[serde(default)]
60 pub object: Option<String>,
61 /// The ephemeral client secret used to open the WebSocket
62 /// connection.
63 pub client_secret: RealtimeClientSecret,
64 /// The full effective session configuration, as raw JSON.
65 #[serde(default)]
66 pub session: Option<serde_json::Value>,
67}
68
69crate::impl_from_str!(RealtimeSession);
70
71impl Post for CreateRealtimeSessionRequest {
72 fn is_streaming(&self) -> bool {
73 false
74 }
75
76 /// Builds the URL for the request.
77 ///
78 /// `base_url` should be like <https://api.openai.com/v1>
79 fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
80 let mut url = Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
81 url.path_segments_mut()
82 .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
83 .push("realtime")
84 .push("sessions");
85 Ok(url.to_string())
86 }
87}
88
89impl PostNoStream for CreateRealtimeSessionRequest {
90 type Response = RealtimeSession;
91}