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";
20pub const EVENT_SPEECH_STARTED: &str = "input_audio_buffer.speech_started";
21pub const EVENT_SPEECH_STOPPED: &str = "input_audio_buffer.speech_stopped";
22pub const EVENT_TRANSCRIPT_DELTA: &str = "conversation.item.input_audio_transcription.delta";
23pub const EVENT_TURN_EOU_PREDICTED: &str = "turn.eou.predicted";
24
25pub type EventData = Map<String, Value>;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum ConnectionState {
29    Disconnected,
30    Connecting,
31    Connected,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ChannelState {
36    Idle,
37    Joining,
38    Joined,
39    Closed,
40    Declined,
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub struct RtcIceServer {
45    pub urls: Value,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub username: Option<String>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    pub credential: Option<String>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
53pub struct SessionBootstrap {
54    pub session_id: String,
55    pub client_token: String,
56    pub expires_at: String,
57    #[serde(default)]
58    pub join_token_ttl_seconds: u64,
59    #[serde(default)]
60    pub ice_servers: Vec<RtcIceServer>,
61}
62
63#[derive(Debug, Clone, Default)]
64pub struct SessionConfig {
65    pub stt_model: Option<String>,
66    pub tts_model: Option<String>,
67    pub voice: Option<String>,
68    pub turn_profile: Option<String>,
69    pub vad_backend: Option<String>,
70    pub turn_detector: Option<String>,
71    pub extra: EventData,
72}
73
74#[derive(Debug, Clone, Default)]
75pub struct ResponseOptions {
76    pub allow_interruptions: Option<bool>,
77}
78
79#[derive(Debug, Clone)]
80pub struct ClientEventEnvelope {
81    pub event: String,
82    pub payload: Value,
83}
84
85#[derive(Debug, Clone)]
86pub struct WireEvent {
87    pub r#type: String,
88    pub data: EventData,
89    pub session_id: String,
90    pub channel_name: String,
91}
92
93#[derive(Debug, Clone)]
94pub struct SessionAttachedEvent {
95    pub session_id: String,
96    pub channel_name: String,
97    pub data: EventData,
98}
99
100#[derive(Debug, Clone)]
101pub struct SessionCreatedEvent {
102    pub session_id: String,
103    pub channel_name: String,
104    pub data: EventData,
105    pub session: Option<EventData>,
106}
107
108#[derive(Debug, Clone)]
109pub struct TranscriptEvent {
110    pub session_id: String,
111    pub channel_name: String,
112    pub data: EventData,
113    pub transcript: String,
114    pub language: Option<String>,
115    pub start_ms: Option<f64>,
116    pub end_ms: Option<f64>,
117    pub eou_probability: Option<f64>,
118    pub topics: Option<Vec<String>>,
119}
120
121#[derive(Debug, Clone)]
122pub struct TurnStateEvent {
123    pub session_id: String,
124    pub channel_name: String,
125    pub data: EventData,
126    pub state: String,
127    pub previous_state: Option<String>,
128}
129
130#[derive(Debug, Clone)]
131pub struct SpeechStartedEvent {
132    pub session_id: String,
133    pub channel_name: String,
134    pub data: EventData,
135    pub timestamp_ms: Option<f64>,
136}
137
138#[derive(Debug, Clone)]
139pub struct SpeechStoppedEvent {
140    pub session_id: String,
141    pub channel_name: String,
142    pub data: EventData,
143    pub timestamp_ms: Option<f64>,
144}
145
146#[derive(Debug, Clone)]
147pub struct TranscriptDeltaEvent {
148    pub session_id: String,
149    pub channel_name: String,
150    pub data: EventData,
151    pub delta: String,
152    pub start_ms: Option<f64>,
153    pub end_ms: Option<f64>,
154}
155
156#[derive(Debug, Clone)]
157pub struct TurnEouPredictedEvent {
158    pub session_id: String,
159    pub channel_name: String,
160    pub data: EventData,
161    pub probability: Option<f64>,
162    pub threshold: Option<f64>,
163    pub delay_ms: Option<f64>,
164    pub start_ms: Option<f64>,
165    pub end_ms: Option<f64>,
166    pub decision: Option<String>,
167    pub action: Option<String>,
168    pub turn_detector: Option<String>,
169}
170
171#[derive(Debug, Clone)]
172pub struct ResponseEvent {
173    pub session_id: String,
174    pub channel_name: String,
175    pub data: EventData,
176    pub response_id: Option<String>,
177}
178
179#[derive(Debug, Clone)]
180pub struct InterruptionEvent {
181    pub response: ResponseEvent,
182    pub vad_active_ms: Option<f64>,
183    pub partial_transcript: Option<String>,
184}
185
186#[derive(Debug, Clone)]
187pub struct BrowserEvent {
188    pub session_id: String,
189    pub channel_name: String,
190    pub data: EventData,
191    pub event: String,
192    pub payload: Value,
193}
194
195#[derive(Debug, Clone)]
196pub struct CloseEvent {
197    pub session_id: String,
198    pub channel_name: String,
199    pub data: EventData,
200    pub reason: String,
201    pub connection_state: Option<String>,
202    pub ice_connection_state: Option<String>,
203    pub data_channel_state: Option<String>,
204}
205
206#[derive(Debug, Clone)]
207pub struct ErrorEvent {
208    pub session_id: String,
209    pub channel_name: String,
210    pub data: EventData,
211    pub message: Option<String>,
212    pub code: Option<String>,
213}
214
215pub(crate) fn optional_string(data: &EventData, key: &str) -> Option<String> {
216    data.get(key).and_then(Value::as_str).map(ToOwned::to_owned)
217}
218
219pub(crate) fn required_string(data: &EventData, key: &str, fallback: &str) -> String {
220    optional_string(data, key)
221        .filter(|s| !s.is_empty())
222        .unwrap_or_else(|| fallback.to_owned())
223}
224
225pub(crate) fn optional_number(data: &EventData, key: &str) -> Option<f64> {
226    data.get(key).and_then(Value::as_f64)
227}
228
229pub(crate) fn optional_string_vec(data: &EventData, key: &str) -> Option<Vec<String>> {
230    data.get(key).and_then(Value::as_array).and_then(|items| {
231        items
232            .iter()
233            .map(|item| item.as_str().map(ToOwned::to_owned))
234            .collect()
235    })
236}