async_openai_wasm/types/realtime/
client_event.rs

1use super::{item::Item, session_resource::SessionResource};
2use serde::{Deserialize, Serialize};
3
4///
5/// A trait same as Into<String>
6///
7/// For converting event structs into text part of WS message
8///
9pub trait ToText {
10    fn to_text(self) -> String;
11}
12
13#[derive(Debug, Serialize, Deserialize, Clone, Default)]
14pub struct SessionUpdateEvent {
15    /// Optional client-generated ID used to identify this event.
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub event_id: Option<String>,
18    /// Session configuration to update.
19    pub session: SessionResource,
20}
21
22#[derive(Debug, Serialize, Deserialize, Clone, Default)]
23pub struct InputAudioBufferAppendEvent {
24    /// Optional client-generated ID used to identify this event.
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub event_id: Option<String>,
27    /// Base64-encoded audio bytes.
28    pub audio: String,
29}
30
31#[derive(Debug, Serialize, Deserialize, Clone, Default)]
32pub struct InputAudioBufferCommitEvent {
33    /// Optional client-generated ID used to identify this event.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub event_id: Option<String>,
36}
37
38#[derive(Debug, Serialize, Deserialize, Clone, Default)]
39pub struct InputAudioBufferClearEvent {
40    /// Optional client-generated ID used to identify this event.
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub event_id: Option<String>,
43}
44
45#[derive(Debug, Serialize, Deserialize, Clone)]
46pub struct ConversationItemCreateEvent {
47    /// Optional client-generated ID used to identify this event.
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub event_id: Option<String>,
50
51    /// The ID of the preceding item after which the new item will be inserted.
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub previous_item_id: Option<String>,
54
55    /// The item to add to the conversation.
56    pub item: Item,
57}
58
59#[derive(Debug, Serialize, Deserialize, Clone, Default)]
60pub struct ConversationItemTruncateEvent {
61    /// Optional client-generated ID used to identify this event.
62    #[serde(skip_serializing_if = "Option::is_none")]
63    pub event_id: Option<String>,
64
65    /// The ID of the assistant message item to truncate.
66    pub item_id: String,
67
68    /// The index of the content part to truncate.
69    pub content_index: u32,
70
71    /// Inclusive duration up to which audio is truncated, in milliseconds.
72    pub audio_end_ms: u32,
73}
74
75#[derive(Debug, Serialize, Deserialize, Clone, Default)]
76pub struct ConversationItemDeleteEvent {
77    /// Optional client-generated ID used to identify this event.
78    #[serde(skip_serializing_if = "Option::is_none")]
79    pub event_id: Option<String>,
80
81    /// The ID of the item to delete.
82    pub item_id: String,
83}
84
85#[derive(Debug, Serialize, Deserialize, Clone, Default)]
86pub struct ResponseCreateEvent {
87    /// Optional client-generated ID used to identify this event.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub event_id: Option<String>,
90
91    /// Configuration for the response.
92    pub response: Option<SessionResource>,
93}
94
95#[derive(Debug, Serialize, Deserialize, Clone, Default)]
96pub struct ResponseCancelEvent {
97    /// Optional client-generated ID used to identify this event.
98    #[serde(skip_serializing_if = "Option::is_none")]
99    pub event_id: Option<String>,
100}
101
102/// These are events that the OpenAI Realtime WebSocket server will accept from the client.
103#[derive(Debug, Serialize, Deserialize)]
104#[serde(tag = "type")]
105pub enum ClientEvent {
106    /// Send this event to update the session’s default configuration.
107    #[serde(rename = "session.update")]
108    SessionUpdate(SessionUpdateEvent),
109
110    /// Send this event to append audio bytes to the input audio buffer.
111    #[serde(rename = "input_audio_buffer.append")]
112    InputAudioBufferAppend(InputAudioBufferAppendEvent),
113
114    /// Send this event to commit audio bytes to a user message.
115    #[serde(rename = "input_audio_buffer.commit")]
116    InputAudioBufferCommit(InputAudioBufferCommitEvent),
117
118    /// Send this event to clear the audio bytes in the buffer.
119    #[serde(rename = "input_audio_buffer.clear")]
120    InputAudioBufferClear(InputAudioBufferClearEvent),
121
122    /// Send this event when adding an item to the conversation.
123    #[serde(rename = "conversation.item.create")]
124    ConversationItemCreate(ConversationItemCreateEvent),
125
126    /// Send this event when you want to truncate a previous assistant message’s audio.
127    #[serde(rename = "conversation.item.truncate")]
128    ConversationItemTruncate(ConversationItemTruncateEvent),
129
130    /// Send this event when you want to remove any item from the conversation history.
131    #[serde(rename = "conversation.item.delete")]
132    ConversationItemDelete(ConversationItemDeleteEvent),
133
134    /// Send this event to trigger a response generation.
135    #[serde(rename = "response.create")]
136    ResponseCreate(ResponseCreateEvent),
137
138    /// Send this event to cancel an in-progress response.
139    #[serde(rename = "response.cancel")]
140    ResponseCancel(ResponseCancelEvent),
141}
142
143impl From<&ClientEvent> for String {
144    fn from(value: &ClientEvent) -> Self {
145        serde_json::to_string(value).unwrap()
146    }
147}
148
149macro_rules! event_struct_to_variant {
150    ($from_typ:ty, $evt_typ:ty, $variant:ident) => {
151        impl From<$from_typ> for $evt_typ {
152            fn from(value: $from_typ) -> Self {
153                <$evt_typ>::$variant(value)
154            }
155        }
156    };
157}
158
159event_struct_to_variant!(SessionUpdateEvent, ClientEvent, SessionUpdate);
160event_struct_to_variant!(
161    InputAudioBufferAppendEvent,
162    ClientEvent,
163    InputAudioBufferAppend
164);
165event_struct_to_variant!(
166    InputAudioBufferCommitEvent,
167    ClientEvent,
168    InputAudioBufferCommit
169);
170event_struct_to_variant!(
171    InputAudioBufferClearEvent,
172    ClientEvent,
173    InputAudioBufferClear
174);
175event_struct_to_variant!(
176    ConversationItemCreateEvent,
177    ClientEvent,
178    ConversationItemCreate
179);
180event_struct_to_variant!(
181    ConversationItemTruncateEvent,
182    ClientEvent,
183    ConversationItemTruncate
184);
185event_struct_to_variant!(
186    ConversationItemDeleteEvent,
187    ClientEvent,
188    ConversationItemDelete
189);
190event_struct_to_variant!(ResponseCreateEvent, ClientEvent, ResponseCreate);
191event_struct_to_variant!(ResponseCancelEvent, ClientEvent, ResponseCancel);
192
193impl<T: Into<ClientEvent>> ToText for T {
194    // blanket impl for all client event structs
195    fn to_text(self) -> String {
196        (&self.into()).into()
197    }
198}
199
200impl From<Item> for ConversationItemCreateEvent {
201    fn from(value: Item) -> Self {
202        Self {
203            event_id: None,
204            previous_item_id: None,
205            item: value,
206        }
207    }
208}