Skip to main content

vox_rtc_server/
types.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{Map, Value};
3
4pub const EVENT_CLIENT_EVENT: &str = "client.event";
5pub const EVENT_BROWSER_EVENT: &str = "browser.event";
6pub const EVENT_RTC_CLIENT_DISCONNECTED: &str = "rtc.client.disconnected";
7pub const EVENT_ERROR: &str = "error";
8pub const EVENT_INTERRUPTION_DETECTED: &str = "interruption.detected";
9pub const EVENT_INTERRUPTION_FALSE_POSITIVE: &str = "interruption.false_positive";
10pub const EVENT_RESPONSE_AUDIO_CLEAR: &str = "response.audio.clear";
11pub const EVENT_RESPONSE_CANCELLED: &str = "response.cancelled";
12pub const EVENT_RESPONSE_COMMITTED: &str = "response.committed";
13pub const EVENT_RESPONSE_CREATED: &str = "response.created";
14pub const EVENT_RESPONSE_DONE: &str = "response.done";
15pub const EVENT_RTC_SESSION_ATTACHED: &str = "rtc.session.attached";
16pub const EVENT_SESSION_CREATED: &str = "session.created";
17pub const EVENT_TRANSCRIPT_COMPLETED: &str =
18    "conversation.item.input_audio_transcription.completed";
19pub const EVENT_TURN_STATE_CHANGED: &str = "turn.state_changed";
20
21pub type EventData = Map<String, Value>;
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum ConnectionState {
25    Disconnected,
26    Connecting,
27    Connected,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub enum ChannelState {
32    Idle,
33    Joining,
34    Joined,
35    Closed,
36    Declined,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
40pub struct RtcIceServer {
41    pub urls: Value,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    pub username: Option<String>,
44    #[serde(default, skip_serializing_if = "Option::is_none")]
45    pub credential: Option<String>,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
49pub struct SessionBootstrap {
50    pub session_id: String,
51    pub client_token: String,
52    pub expires_at: String,
53    #[serde(default)]
54    pub join_token_ttl_seconds: u64,
55    #[serde(default)]
56    pub ice_servers: Vec<RtcIceServer>,
57}
58
59#[derive(Debug, Clone, Default)]
60pub struct SessionConfig {
61    pub stt_model: Option<String>,
62    pub tts_model: Option<String>,
63    pub voice: Option<String>,
64    pub turn_profile: Option<String>,
65    pub vad_backend: Option<String>,
66    pub turn_detector: Option<String>,
67    pub extra: EventData,
68}
69
70#[derive(Debug, Clone, Default)]
71pub struct ResponseOptions {
72    pub allow_interruptions: Option<bool>,
73}
74
75#[derive(Debug, Clone)]
76pub struct ClientEventEnvelope {
77    pub event: String,
78    pub payload: Value,
79}
80
81#[derive(Debug, Clone)]
82pub struct WireEvent {
83    pub r#type: String,
84    pub data: EventData,
85    pub session_id: String,
86    pub channel_name: String,
87}
88
89#[derive(Debug, Clone)]
90pub struct SessionAttachedEvent {
91    pub session_id: String,
92    pub channel_name: String,
93    pub data: EventData,
94}
95
96#[derive(Debug, Clone)]
97pub struct SessionCreatedEvent {
98    pub session_id: String,
99    pub channel_name: String,
100    pub data: EventData,
101    pub session: Option<EventData>,
102}
103
104#[derive(Debug, Clone)]
105pub struct TranscriptEvent {
106    pub session_id: String,
107    pub channel_name: String,
108    pub data: EventData,
109    pub transcript: String,
110    pub language: Option<String>,
111    pub start_ms: Option<f64>,
112    pub end_ms: Option<f64>,
113    pub eou_probability: Option<f64>,
114    pub topics: Option<Vec<String>>,
115}
116
117#[derive(Debug, Clone)]
118pub struct TurnStateEvent {
119    pub session_id: String,
120    pub channel_name: String,
121    pub data: EventData,
122    pub state: String,
123    pub previous_state: Option<String>,
124}
125
126#[derive(Debug, Clone)]
127pub struct ResponseEvent {
128    pub session_id: String,
129    pub channel_name: String,
130    pub data: EventData,
131    pub response_id: Option<String>,
132}
133
134#[derive(Debug, Clone)]
135pub struct InterruptionEvent {
136    pub response: ResponseEvent,
137    pub vad_active_ms: Option<f64>,
138    pub partial_transcript: Option<String>,
139}
140
141#[derive(Debug, Clone)]
142pub struct BrowserEvent {
143    pub session_id: String,
144    pub channel_name: String,
145    pub data: EventData,
146    pub event: String,
147    pub payload: Value,
148}
149
150#[derive(Debug, Clone)]
151pub struct CloseEvent {
152    pub session_id: String,
153    pub channel_name: String,
154    pub data: EventData,
155    pub reason: String,
156    pub connection_state: Option<String>,
157    pub ice_connection_state: Option<String>,
158    pub data_channel_state: Option<String>,
159}
160
161#[derive(Debug, Clone)]
162pub struct ErrorEvent {
163    pub session_id: String,
164    pub channel_name: String,
165    pub data: EventData,
166    pub message: Option<String>,
167    pub code: Option<String>,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub(crate) struct SocketEnvelope {
172    pub action: String,
173    pub event: String,
174    #[serde(default)]
175    pub payload: Value,
176    #[serde(rename = "channelName")]
177    pub channel_name: String,
178    #[serde(rename = "requestId")]
179    pub request_id: String,
180}
181
182pub(crate) fn object_to_map(value: Value) -> EventData {
183    match value {
184        Value::Object(map) => map,
185        other => {
186            let mut map = Map::new();
187            map.insert("payload".to_owned(), other);
188            map
189        }
190    }
191}
192
193pub(crate) fn optional_string(data: &EventData, key: &str) -> Option<String> {
194    data.get(key).and_then(Value::as_str).map(ToOwned::to_owned)
195}
196
197pub(crate) fn required_string(data: &EventData, key: &str, fallback: &str) -> String {
198    optional_string(data, key)
199        .filter(|s| !s.is_empty())
200        .unwrap_or_else(|| fallback.to_owned())
201}
202
203pub(crate) fn optional_number(data: &EventData, key: &str) -> Option<f64> {
204    data.get(key).and_then(Value::as_f64)
205}
206
207pub(crate) fn optional_string_vec(data: &EventData, key: &str) -> Option<Vec<String>> {
208    data.get(key).and_then(Value::as_array).and_then(|items| {
209        items
210            .iter()
211            .map(|item| item.as_str().map(ToOwned::to_owned))
212            .collect()
213    })
214}