Skip to main content

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::{Deserialize, 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, Deserialize)]
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, default, skip_serializing_if = "Option::is_none")]
42    pub extra_body_map: Option<serde_json::Map<String, serde_json::Value>>,
43}
44
45/// A client secret of a Realtime session.
46#[derive(Debug, Clone, serde::Serialize, 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::Serialize, 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}