1use serde::{de, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
4
5use crate::common::models::LiveModel;
6use crate::responses::request::{ReasoningEffort, ReasoningSummary};
7
8#[derive(Debug, Clone, PartialEq, Eq, Default)]
10#[non_exhaustive]
11pub enum LiveVoice {
12 Alloy,
13 Ash,
14 Ballad,
15 Beacon,
16 Bossa,
17 Cedar,
18 Cinder,
19 Coral,
20 Delta,
21 Echo,
22 Gleam,
23 #[default]
24 Marin,
25 Meridian,
26 Quartz,
27 Ripple,
28 Sage,
29 Shimmer,
30 Stone,
31 Tempo,
32 Verse,
33 Vesper,
34 Willow,
35 Custom {
37 id: String,
38 },
39}
40
41impl LiveVoice {
42 fn built_in_name(&self) -> Option<&'static str> {
43 match self {
44 Self::Alloy => Some("alloy"),
45 Self::Ash => Some("ash"),
46 Self::Ballad => Some("ballad"),
47 Self::Beacon => Some("beacon"),
48 Self::Bossa => Some("bossa"),
49 Self::Cedar => Some("cedar"),
50 Self::Cinder => Some("cinder"),
51 Self::Coral => Some("coral"),
52 Self::Delta => Some("delta"),
53 Self::Echo => Some("echo"),
54 Self::Gleam => Some("gleam"),
55 Self::Marin => Some("marin"),
56 Self::Meridian => Some("meridian"),
57 Self::Quartz => Some("quartz"),
58 Self::Ripple => Some("ripple"),
59 Self::Sage => Some("sage"),
60 Self::Shimmer => Some("shimmer"),
61 Self::Stone => Some("stone"),
62 Self::Tempo => Some("tempo"),
63 Self::Verse => Some("verse"),
64 Self::Vesper => Some("vesper"),
65 Self::Willow => Some("willow"),
66 Self::Custom { .. } => None,
67 }
68 }
69
70 fn from_built_in(name: &str) -> Option<Self> {
71 Some(match name {
72 "alloy" => Self::Alloy,
73 "ash" => Self::Ash,
74 "ballad" => Self::Ballad,
75 "beacon" => Self::Beacon,
76 "bossa" => Self::Bossa,
77 "cedar" => Self::Cedar,
78 "cinder" => Self::Cinder,
79 "coral" => Self::Coral,
80 "delta" => Self::Delta,
81 "echo" => Self::Echo,
82 "gleam" => Self::Gleam,
83 "marin" => Self::Marin,
84 "meridian" => Self::Meridian,
85 "quartz" => Self::Quartz,
86 "ripple" => Self::Ripple,
87 "sage" => Self::Sage,
88 "shimmer" => Self::Shimmer,
89 "stone" => Self::Stone,
90 "tempo" => Self::Tempo,
91 "verse" => Self::Verse,
92 "vesper" => Self::Vesper,
93 "willow" => Self::Willow,
94 _ => return None,
95 })
96 }
97}
98
99impl Serialize for LiveVoice {
100 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
101 where
102 S: Serializer,
103 {
104 if let Some(name) = self.built_in_name() {
105 serializer.serialize_str(name)
106 } else if let Self::Custom { id } = self {
107 #[derive(Serialize)]
108 struct CustomVoice<'a> {
109 id: &'a str,
110 }
111 CustomVoice { id }.serialize(serializer)
112 } else {
113 unreachable!("all LiveVoice variants are handled")
114 }
115 }
116}
117
118impl<'de> Deserialize<'de> for LiveVoice {
119 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
120 where
121 D: Deserializer<'de>,
122 {
123 #[derive(Deserialize)]
124 #[serde(untagged)]
125 enum VoiceValue {
126 BuiltIn(String),
127 Custom { id: String },
128 }
129
130 match VoiceValue::deserialize(deserializer)? {
131 VoiceValue::BuiltIn(name) => Self::from_built_in(&name).ok_or_else(|| de::Error::unknown_variant(&name, &[])),
132 VoiceValue::Custom { id } => Ok(Self::Custom { id }),
133 }
134 }
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
139#[non_exhaustive]
140pub enum LiveAudioEncoding {
141 #[serde(rename = "audio/pcm")]
142 Pcm,
143 #[serde(rename = "audio/pcmu")]
144 Pcmu,
145 #[serde(rename = "audio/pcma")]
146 Pcma,
147 #[serde(untagged)]
149 Other(String),
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
154pub struct LiveAudioFormat {
155 #[serde(rename = "type")]
157 pub encoding: LiveAudioEncoding,
158 pub rate: u32,
160}
161
162impl LiveAudioFormat {
163 pub const fn pcm24k() -> Self {
165 Self { encoding: LiveAudioEncoding::Pcm, rate: 24_000 }
166 }
167
168 pub const fn pcm16k() -> Self {
170 Self { encoding: LiveAudioEncoding::Pcm, rate: 16_000 }
171 }
172
173 pub const fn pcmu() -> Self {
175 Self { encoding: LiveAudioEncoding::Pcmu, rate: 8_000 }
176 }
177
178 pub const fn pcma() -> Self {
180 Self { encoding: LiveAudioEncoding::Pcma, rate: 8_000 }
181 }
182}
183
184#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
186pub struct LiveAudioConfig {
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub format: Option<LiveAudioFormat>,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub output: Option<LiveAudioOutputConfig>,
191}
192
193#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
195pub struct LiveAudioOutputConfig {
196 #[serde(skip_serializing_if = "Option::is_none")]
197 pub voice: Option<LiveVoice>,
198}
199
200#[derive(Debug, Clone)]
202pub enum Delegation {
203 Client,
205 Responses(ResponsesDelegationConfig),
207}
208
209impl Delegation {
210 pub fn responses(config: ResponsesDelegationConfig) -> Self {
212 Self::Responses(config)
213 }
214}
215
216impl Serialize for Delegation {
217 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
218 where
219 S: Serializer,
220 {
221 match self {
222 Self::Client => {
223 let mut state = serializer.serialize_struct("Delegation", 1)?;
224 state.serialize_field("type", "client")?;
225 state.end()
226 }
227 Self::Responses(config) => {
228 let mut state = serializer.serialize_struct("Delegation", 2)?;
229 state.serialize_field("type", "responses")?;
230 state.serialize_field("responses", config)?;
231 state.end()
232 }
233 }
234 }
235}
236
237#[derive(Debug, Clone, Serialize)]
239pub struct ResponsesDelegationConfig {
240 pub model: String,
241 #[serde(skip_serializing_if = "Option::is_none")]
242 pub instructions: Option<String>,
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub max_output_tokens: Option<u32>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub parallel_tool_calls: Option<bool>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub reasoning: Option<ResponsesReasoningConfig>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub service_tier: Option<serde_json::Value>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub text: Option<ResponsesTextConfig>,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub tool_choice: Option<serde_json::Value>,
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub tools: Option<serde_json::Value>,
257}
258
259#[derive(Debug, Clone, Default, Serialize)]
261pub struct ResponsesReasoningConfig {
262 #[serde(skip_serializing_if = "Option::is_none")]
263 pub effort: Option<ReasoningEffort>,
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub summary: Option<ReasoningSummary>,
266}
267
268#[derive(Debug, Clone, Default, Serialize)]
270pub struct ResponsesTextConfig {
271 #[serde(skip_serializing_if = "Option::is_none")]
272 pub verbosity: Option<String>,
273}
274
275#[derive(Debug, Clone, Default, Serialize)]
277pub struct LiveSessionConfig {
278 #[serde(skip_serializing_if = "Option::is_none")]
279 pub model: Option<LiveModel>,
280 #[serde(skip_serializing_if = "Option::is_none")]
281 pub instructions: Option<String>,
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub audio: Option<LiveAudioConfig>,
284 #[serde(skip_serializing_if = "Option::is_none")]
285 pub delegation: Option<Delegation>,
286 #[serde(skip_serializing_if = "Option::is_none")]
287 pub input: Option<Vec<serde_json::Value>>,
288 #[serde(skip_serializing_if = "Option::is_none")]
289 pub store: Option<bool>,
290}
291
292#[derive(Debug, Clone, Serialize)]
294pub struct LiveSessionUpdate {
295 pub delegation: Delegation,
296}