gproxy_protocol/wire/openai/realtime/
rtc.rs1use super::session::RealtimeSessionCreateRequest;
4use crate::{
5 WireRequest, WireResponse,
6 connection::{HttpBody, MultipartPart},
7};
8
9#[derive(Debug, gproxy_protocol_macros::WireBuilder)]
10#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
11#[derive(gproxy_protocol_macros::DeclaredFields)]
12#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
13pub struct CreateRealtimeCallMultipartForm {
14 pub sdp: MultipartPart,
15 pub session: Option<RealtimeSessionCreateRequest>,
16}
17pub type CreateRealtimeCallRequest = WireRequest<CreateRealtimeCallMultipartForm>;
18pub type CreateRealtimeCallResponse = WireResponse<HttpBody>;
19pub type RealtimeCallSessionJson = RealtimeSessionCreateRequest;
21
22#[derive(
26 Debug,
27 Clone,
28 PartialEq,
29 serde::Serialize,
30 serde::Deserialize,
31 gproxy_protocol_macros::WireBuilder,
32 gproxy_protocol_macros::DeclaredFields,
33)]
34#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
35#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
36pub struct LiveSessionCreateRequest {
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub model: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub instructions: Option<String>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 pub audio: Option<super::RealtimeAudioConfig>,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 pub delegation: Option<LiveDelegation>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 pub initial_items: Option<Vec<LiveInitialMessage>>,
47 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
48 pub rest: crate::Rest,
49}
50
51#[derive(
52 Debug,
53 Clone,
54 PartialEq,
55 serde::Serialize,
56 serde::Deserialize,
57 gproxy_protocol_macros::WireBuilder,
58 gproxy_protocol_macros::DeclaredFields,
59)]
60#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62pub struct LiveDelegation {
63 #[serde(rename = "type")]
64 pub type_: String,
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub ack_filler: Option<bool>,
67 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
68 pub rest: crate::Rest,
69}
70
71#[derive(
72 Debug,
73 Clone,
74 PartialEq,
75 serde::Serialize,
76 serde::Deserialize,
77 gproxy_protocol_macros::WireBuilder,
78 gproxy_protocol_macros::DeclaredFields,
79)]
80#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
81#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
82pub struct LiveInitialMessage {
83 #[serde(rename = "type")]
84 pub type_: String,
85 pub role: String,
86 pub content: Vec<LiveInitialText>,
87 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
88 pub rest: crate::Rest,
89}
90
91#[derive(
92 Debug,
93 Clone,
94 PartialEq,
95 serde::Serialize,
96 serde::Deserialize,
97 gproxy_protocol_macros::WireBuilder,
98 gproxy_protocol_macros::DeclaredFields,
99)]
100#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
101#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
102pub struct LiveInitialText {
103 #[serde(rename = "type")]
104 pub type_: String,
105 pub text: String,
106 #[serde(default, flatten, skip_serializing_if = "serde_json::Map::is_empty")]
107 pub rest: crate::Rest,
108}
109
110#[derive(Debug, gproxy_protocol_macros::WireBuilder, gproxy_protocol_macros::DeclaredFields)]
111#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
112#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
113pub struct CreateLiveCallMultipartForm {
114 pub sdp: MultipartPart,
115 pub session: LiveSessionCreateRequest,
116}
117pub type CreateLiveCallRequest = WireRequest<CreateLiveCallMultipartForm>;
118pub type CreateLiveCallResponse = WireResponse<HttpBody>;
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
124pub enum RealtimeRoute<'a> {
125 CreateCall,
126 CreateLiveCall,
127 Connect,
128 Live { call_id: Option<&'a str> },
129}
130impl<'a> RealtimeRoute<'a> {
131 pub fn from_request(method: &http::Method, path: &'a str) -> Option<Self> {
133 let route = Self::from_path(path)?;
134 match (method, route) {
135 (&http::Method::POST, Self::Live { call_id: None }) => Some(Self::CreateLiveCall),
136 (&http::Method::POST, Self::CreateCall) => Some(route),
137 (&http::Method::GET, Self::Connect | Self::Live { .. }) => Some(route),
138 _ => None,
139 }
140 }
141 pub fn from_path(path: &'a str) -> Option<Self> {
144 let path = path.strip_prefix("/v1/").unwrap_or(path);
145 let path = path.trim_start_matches('/').trim_end_matches('/');
146 match path {
147 "realtime/calls" => Some(Self::CreateCall),
148 "realtime" => Some(Self::Connect),
149 "live" => Some(Self::Live { call_id: None }),
150 _ => path
151 .strip_prefix("live/")
152 .filter(|id| !id.is_empty() && !id.contains('/') && !matches!(*id, "." | ".."))
153 .map(|id| Self::Live { call_id: Some(id) }),
154 }
155 }
156 pub fn operation(self) -> crate::OperationKey {
157 crate::OperationKey {
158 operation: match self {
159 Self::CreateCall | Self::CreateLiveCall => crate::Operation::CreateRealtimeCall,
160 _ => crate::Operation::ConnectRealtime,
161 },
162 dialect: crate::Dialect::OpenAi,
163 }
164 }
165}